Overall Statistics |
Total Trades 976 Average Win 0.32% Average Loss -0.19% Compounding Annual Return 8.352% Drawdown 10.800% Expectancy 0.142 Net Profit 8.152% Sharpe Ratio 0.535 Loss Rate 58% Win Rate 42% Profit-Loss Ratio 1.74 Alpha 0.069 Beta 0.046 Annual Standard Deviation 0.14 Annual Variance 0.02 Information Ratio -0.335 Tracking Error 0.152 Treynor Ratio 1.631 Total Fees $985.57 |
using System.Drawing; using System.Threading; using System.Threading.Tasks; namespace QuantConnect { public partial class Spread : QCAlgorithm { [Parameter] public decimal iStopPercents = 0.01m; [Parameter] public decimal iMinSpread = 1m; [Parameter] public int iPeriodSlow = 50; [Parameter] public int iPeriodFast = 1; [Parameter] public string iSymbol1 = "XIV"; [Parameter] public string iSymbol2 = "VXX"; ExponentialMovingAverage iFma1 = null; ExponentialMovingAverage iSma1 = null; ExponentialMovingAverage iFma2 = null; ExponentialMovingAverage iSma2 = null; CompositeIndicator<IndicatorDataPoint> iOsc1 = null; CompositeIndicator<IndicatorDataPoint> iOsc2 = null; CompositeIndicator<IndicatorDataPoint> iSpread = null; StandardDeviation iDev1 = null; StandardDeviation iDev2 = null; StandardDeviation iDev = null; decimal iBalance = 10000m; string iChartName = "Deals"; int iDirection = 0; int iOrderId = 0; public class iDeal { public int SL; public int TP; public int Market; }; Dictionary<int, iDeal> iDeals = new Dictionary<int, iDeal>(); public override void Initialize() { var resolution = Resolution.Hour; SetCash(iBalance); SetWarmUp(iPeriodSlow); //SetStartDate(2008, 1, 1); //SetEndDate(2009, 12, 1); SetStartDate(2017, 1, 1); SetEndDate(DateTime.Now.Date); SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage); AddSecurity(SecurityType.Equity, iSymbol1, resolution, true, 4m, false); AddSecurity(SecurityType.Equity, iSymbol2, resolution, true, 4m, false); iFma1 = EMA(iSymbol1, iPeriodFast, resolution); iSma1 = EMA(iSymbol1, iPeriodSlow, resolution); iFma2 = EMA(iSymbol2, iPeriodFast, resolution); iSma2 = EMA(iSymbol2, iPeriodSlow, resolution); iOsc1 = iSma1.Minus(iFma1); iOsc2 = iSma2.Minus(iFma2); iSpread = iOsc1.Minus(iOsc2); var deviation = new StandardDeviation(iPeriodSlow); iDev = deviation.Of(iOsc2.Minus(iOsc1)); iDev1 = STD(iSymbol1, iPeriodSlow); iDev2 = STD(iSymbol2, iPeriodSlow); var chart = new Chart(iChartName); var seriesStock1 = new Series("Stock #1", SeriesType.Line, 0) { Color = Color.Gray }; var seriesBuy1 = new Series("Buy #1", SeriesType.Scatter, 0) { Color = Color.Blue, ScatterMarkerSymbol = ScatterMarkerSymbol.Triangle }; var seriesSell1 = new Series("Sell #1", SeriesType.Scatter, 0) { Color = Color.Red, ScatterMarkerSymbol = ScatterMarkerSymbol.TriangleDown }; var seriesStock2 = new Series("Stock #2", SeriesType.Line, 1) { Color = Color.Gray }; var seriesBuy2 = new Series("Buy #2", SeriesType.Scatter, 1) { Color = Color.Blue, ScatterMarkerSymbol = ScatterMarkerSymbol.Triangle }; var seriesSell2 = new Series("Sell #2", SeriesType.Scatter, 1) { Color = Color.Red, ScatterMarkerSymbol = ScatterMarkerSymbol.TriangleDown }; var seriesBalance = new Series("Balance", SeriesType.Line, 2) { Color = Color.Yellow }; var seriesOsc1 = new Series("Osc #1", SeriesType.Line, 3) { Color = Color.Blue }; var seriesOsc2 = new Series("Osc #2", SeriesType.Line, 3) { Color = Color.Red }; var seriesSpread = new Series("Spread", SeriesType.Line, 4) { Color = Color.Lime }; var seriesDevUp = new Series("Dev Up x 2", SeriesType.Line, 4) { Color = Color.Blue }; var seriesDevDown = new Series("Dev Dn x 2", SeriesType.Line, 4) { Color = Color.Red }; chart.AddSeries(seriesStock1); chart.AddSeries(seriesBuy1); chart.AddSeries(seriesSell1); chart.AddSeries(seriesStock2); chart.AddSeries(seriesBuy2); chart.AddSeries(seriesSell2); chart.AddSeries(seriesBalance); chart.AddSeries(seriesOsc1); chart.AddSeries(seriesOsc2); chart.AddSeries(seriesSpread); chart.AddSeries(seriesDevUp); chart.AddSeries(seriesDevDown); AddChart(chart); } public void OnData(TradeBars data) { if (data.Count < 2) { return; } Plot(iChartName, "Stock #1", data[iSymbol1].Price); Plot(iChartName, "Stock #2", data[iSymbol2].Price); Plot(iChartName, "Balance", iBalance); Plot(iChartName, "Osc #1", iOsc1); Plot(iChartName, "Osc #2", iOsc2); Plot(iChartName, "Spread", iSpread); Plot(iChartName, "Dev Up x 2", iDev * 2); Plot(iChartName, "Dev Dn x 2", iDev * 2 * -1); var direction = CanOpen(); var update = CanUpdate(); var balance = iBalance / 4; if (update != 0) { direction = iDirection; } var ratio = Math.Max(iDev1, 0.01m) / Math.Max(iDev2, 0.01m); var volume1 = balance; var volume2 = balance; volume1 = ratio > 1 ? volume1 / ratio : volume1; volume2 = ratio < 1 ? volume2 / ratio : volume2; volume1 = Convert.ToDecimal(volume1 / data[iSymbol1].Close); volume2 = Convert.ToDecimal(volume2 / data[iSymbol2].Close); if (direction > 0 && volume1 > 1 && volume2 > 1) { iDirection = direction; Plot(iChartName, "Sell #1", Securities[iSymbol1].Close); Plot(iChartName, "Buy #2", Securities[iSymbol2].Close); Action(iSymbol1, volume1, -1); Action(iSymbol2, volume2, 1); return; } if (direction < 0 && volume1 > 1 && volume2 > 1) { iDirection = direction; Plot(iChartName, "Buy #1", Securities[iSymbol1].Close); Plot(iChartName, "Sell #2", Securities[iSymbol2].Close); Action(iSymbol1, volume1, 1); Action(iSymbol2, volume2, -1); return; } if (CanClose() == 1) { Liquidate(); return; } } protected OrderTicket Action(string symbol, decimal volume, int direction) { var operation = (direction > 0 ? "Buy #" : "Sell #") + (++iOrderId); var ticket = MarketOrder(symbol, volume * direction, false, operation); iDeals[ticket.OrderId] = new iDeal { Market = ticket.OrderId }; var process = new Thread(() => { Transactions.WaitForOrder(ticket.OrderId); if (Transactions.GetOrderById(ticket.OrderId).Status != OrderStatus.Filled) { return; } var price = Securities[symbol].Price; //var orderSL = StopMarketOrder(symbol, -volume * direction, price - 5m * direction, "SL #" + ticket.OrderId.ToString()); //var orderTP = LimitOrder(symbol, -volume * direction, price + iIncomePips * direction, "TP #" + ticket.OrderId.ToString()); //iDeals[ticket.OrderId].SL = orderSL.OrderId; //iDeals[ticket.OrderId].TP = orderTP.OrderId; }); process.Start(); return ticket; } protected int GetDirection(decimal level) { var deviation = Math.Max(Math.Abs(iDev) * level, iMinSpread); var spread = Math.Abs(iSpread); if (IsWarmingUp == false && iSpread.IsReady && iDev.IsReady && spread > deviation) { if (iOsc1 > iOsc2) { return 1; } if (iOsc1 < iOsc2) { return -1; } } return 0; } protected int CanOpen() { if (Portfolio.Invested == false) { return GetDirection(2.0m); } return 0; } protected int CanUpdate() { if (Portfolio.Invested && iDirection == GetDirection(3.0m)) { return iDirection; } return 0; } protected int CanClose() { var balance = GetBalance(0); var direction = GetDirection(2.0m); var isStop = Math.Abs(balance) > iBalance * iStopPercents; var isUp = iDirection < 0 && direction > 0; var isDown = iDirection > 0 && direction < 0; if (isUp || isDown || isStop) { iDirection = 0; iBalance += Portfolio.TotalUnrealizedProfit; return 1; } return 0; } protected decimal GetBalance(decimal balance) { return balance + Portfolio.TotalUnrealizedProfit + Portfolio.TotalProfit - Portfolio.TotalFees; } } }