Overall Statistics |
Total Trades 2 Average Win 0% Average Loss -0.76% Compounding Annual Return -97.986% Drawdown 1.100% Expectancy -1 Net Profit -0.755% Sharpe Ratio 0 Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.50 |
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.Linq; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Orders; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// This regression algorithm checks if all the option chain data coming to the algo is consistent with current securities manager state /// </summary> public class TestAlgorithm2 : QCAlgorithm { private const string UnderlyingTicker = "SPY"; public readonly Symbol Underlying = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Equity, Market.USA); public readonly Symbol OptionSymbol = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Option, Market.USA); public override void Initialize() { SetStartDate(2015, 12, 24); SetEndDate(2015, 12, 24); SetCash(10000); var equity = AddEquity(UnderlyingTicker); var option = AddOption(UnderlyingTicker); // set our strike/expiry filter for this option chain option.SetFilter(u => u.IncludeWeeklys() .Strikes(-2, +2) .Expiration(TimeSpan.Zero, TimeSpan.FromDays(10))); // use the underlying equity as the benchmark SetBenchmark(equity.Symbol); } /// <summary> /// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event /// </summary> /// <param name="slice">The current slice of data keyed by symbol string</param> public override void OnData(Slice slice) { if (!Portfolio.Invested) { OptionChain chain; if (slice.OptionChains.TryGetValue(OptionSymbol, out chain)) { // check if data is consistent foreach (var o in chain) { Log(string.Format("chain:{0} Bid:{1} Ask:{2} IV:{3}", o.Symbol, o.BidPrice, o.AskPrice, o.ImpliedVolatility)); if (!Securities.ContainsKey(o.Symbol)) { // inconsistency found: option chains contains contract information that is not available in securities manager and not available for trading throw new Exception(string.Format("inconsistency found: option chains contains contract {0} that is not available in securities manager and not available for trading", o.Symbol.Value)); } } // trade var contract = ( from optionContract in chain.OrderByDescending(x => x.Strike) where optionContract.Right == OptionRight.Call where optionContract.Expiry == Time.Date where optionContract.Strike < chain.Underlying.Price select optionContract ).Skip(2).FirstOrDefault(); if (contract != null) { MarketOrder(contract.Symbol, 1); MarketOnCloseOrder(contract.Symbol, -1); } } } } /// <summary> /// Order fill event handler. On an order fill update the resulting information is passed to this method. /// </summary> /// <param name="orderEvent">Order event details containing details of the evemts</param> /// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks> public override void OnOrderEvent(OrderEvent orderEvent) { Log(orderEvent.ToString()); } } }
using System.Collections.Concurrent; namespace QuantConnect { /* * Relative Strength Index Indicator: * * 100 * RSI = 100 - ------------ * 1 + RS * * Where RS = Avg of X Period Close Up / Absolute(Avg) X of Period Close Down. * */ public class RelativeStrengthIndexCustom { //Public Access to the RSI Output public decimal RSI { get { return (100 - (100 / (1 + _rs))); } } //Public Access to Know if RSI Indicator Ready public bool Ready { get { return (_upward.Count >= _period) && (_downward.Count >= _period); } } //Private Class Variables: private decimal _rs = 0; private bool _ema = false; private decimal _period = 14; private decimal _joinBars = 1; private Candle _superCandle = new Candle(); private Candle _previousCandle = new Candle(); private FixedSizedQueue<decimal> _downward = new FixedSizedQueue<decimal>(0); private FixedSizedQueue<decimal> _upward = new FixedSizedQueue<decimal>(0); private decimal _upwardSum = 0, _avgUpward = 0; private decimal _downwardSum = 0, _avgDownward = 0; //Initialize the RSI with 'period' candles public RelativeStrengthIndexCustom(int period, int joinBars = 1, bool useEMA = false) { //Range check variables: if (period < 2) period = 2; //Class settings: _period = (decimal)period; // How many samples is the RSI? _ema = useEMA; // Use the EMA average for RSI _joinBars = joinBars; // Join multiple tradebars together //Remember the upward and downward movements in a FIFO queue: _upward = new FixedSizedQueue<decimal>(period); _downward = new FixedSizedQueue<decimal>(period); //Online implementation of SMA - needs moving sum of all components: _upwardSum = 0; _downwardSum = 0; } //Add a new sample to build the RSI Indicator: public void AddSample(TradeBar bar) { //Build a multibar candle, until join reached return. _superCandle.Update(bar); if (_superCandle.Samples < _joinBars) return; //Initialize the first loop. if (_previousCandle.Samples == 0) { _previousCandle = _superCandle; _superCandle = new Candle(); return; } //Get the difference between this bar and previous bar: decimal difference = _superCandle.Close - _previousCandle.Close; //Update the Moving Average Calculations: if (difference >= 0) { if (_ema) { _avgUpward = UpdateDirectionalEMA(ref _upward, difference); _avgDownward = UpdateDirectionalEMA(ref _downward, 0); } else { _avgUpward = UpdateDirectionalSMA(ref _upward, ref _upwardSum, difference); _avgDownward = UpdateDirectionalSMA(ref _downward, ref _downwardSum, 0); } } if (difference <= 0) { difference = Math.Abs(difference); if (_ema) { _avgUpward = UpdateDirectionalEMA(ref _upward, 0); _avgDownward = UpdateDirectionalEMA(ref _downward, difference); } else { _avgUpward = UpdateDirectionalSMA(ref _upward, ref _upwardSum, 0); _avgDownward = UpdateDirectionalSMA(ref _downward, ref _downwardSum, difference); } } //Refresh RS Factor: //RS Index Automatically Updated in the Public Property Above: if (_avgDownward != 0) { _rs = _avgUpward / _avgDownward; } else { _rs = Decimal.MaxValue - 1; } //Reset for next loop: _previousCandle = _superCandle; _superCandle = new Candle(); } // Update the moving average and fixed length queue in a generic fashion to work for up and downward movement. // Return the average. private decimal UpdateDirectionalSMA(ref FixedSizedQueue<decimal> queue, ref decimal sum, decimal sample) { //Increment Sum sum += sample; //If we've shuffled off queue, remove from sum: if(queue.Enqueue(sample)) { sum -= queue.LastDequeued; } //When less than period samples, only divide by the number of samples. if (queue.Count < _period) { return (sum / (decimal)queue.Count); } else { return (sum / _period); } } // Update the moving average and fixed length queue in a generic fashion to work for up and downward movement. // Return the average. private decimal UpdateDirectionalEMA(ref FixedSizedQueue<decimal> queue, decimal sample) { queue.Enqueue(sample); if (queue.Count == 1) { return sample; } else { return (1m / _period) * sample + ((_period - 1m) / _period) * queue.LastEnqueued; } } //Fixed length queue that dumps things off when no more space in queue. private class FixedSizedQueue<T> : ConcurrentQueue<T> { public int Size { get; private set; } public T LastDequeued { get; private set; } public T LastEnqueued {get; private set;} public bool Dequeued { get; private set; } public FixedSizedQueue(int size) { Size = size; } public new bool Enqueue(T obj) { base.Enqueue(obj); LastEnqueued = obj; Dequeued = false; lock (this) { if (base.Count > Size) { T outObj; Dequeued = base.TryDequeue(out outObj); LastDequeued = outObj; } } return Dequeued; } } /// <summary> /// Simple online "super-tradebar" generator for making an OHLC from multiple bars. /// </summary> public class Candle { public decimal Open = 0; public decimal High = Decimal.MinValue; public decimal Low = Decimal.MaxValue; public decimal Close = 0; public int Samples = 0; public void Update(TradeBar bar) { if (Open == 0) Open = bar.Open; if (High < bar.High) High = bar.High; if (Low > bar.Low) Low = bar.Low; Close = bar.Close; Samples++; } } } }