Overall Statistics |
Total Trades 3301 Average Win 1.58% Average Loss -1.59% Compounding Annual Return 2663.811% Drawdown 51.400% Expectancy 0.153 Net Profit 2818.801% Sharpe Ratio 2.967 Loss Rate 42% Win Rate 58% Profit-Loss Ratio 0.99 Alpha 4.898 Beta -159.092 Annual Standard Deviation 0.913 Annual Variance 0.833 Information Ratio 2.952 Tracking Error 0.913 Treynor Ratio -0.017 Total Fees $0.00 |
//Copyright HardingSoftware.com, 2018. //Granted to the public domain. //Use entirely at your own risk. namespace QuantConnect { public class MultiCoinFramework : QCAlgorithm { string tickersString ="BTCUSD,ETHUSD,LTCUSD"; decimal changes1Ratio=-1.0m; //The influence of change upon fitness. decimal changes2Ratio=0.0m; //The influence of change in change upon fitness. int emaOfChanges1Length=24; //The length of the change indicator. int emaOfChanges2Length=24; //The length of the change in change indicator. decimal leverage=1m; int historyLength=2; int changes1Length=2; int changes2Length=2; Resolution resolution=Resolution.Hour; List<StockData> stockDatas = new List<StockData>(); string stockHeld=""; public override void Initialize() { SetStartDate(2017, 3, 1); SetEndDate(2018, 3, 6); SetCash(10000); string[] tickers = tickersString.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries); foreach (string ticker in tickers) { Symbol symbol = QuantConnect.Symbol.Create(ticker, SecurityType.Crypto, Market.GDAX); AddCrypto(symbol, resolution); StockData stockData=new StockData(); stockData.Ticker=ticker; stockData.emaOfChanges1Indicator = new ExponentialMovingAverage(emaOfChanges1Length); stockData.emaOfChanges2Indicator = new ExponentialMovingAverage(emaOfChanges2Length); stockDatas.Add(stockData); } } public void SetHoldings_(Symbol symbol,Decimal ratio) { decimal price = Securities[symbol].Price; var quantity =Securities[symbol].Holdings.Quantity; // Keep 3% Cash (for the limit order, rounding errors, and safety) var keep = .03; var usablePortfolioValue = Portfolio.TotalPortfolioValue * Convert.ToDecimal(1 - keep); // +0.1% Limit Order // (to make sure it executes quickly and without much loss) // (if you set the limit large it will act like a market order) var limit = 1.001; var desiredQuantity = usablePortfolioValue * ratio / price; var orderQuantity = desiredQuantity - quantity; // limit needs to be inverse when selling decimal limitPrice = 0; if (orderQuantity >= 0) { limitPrice = price * Convert.ToDecimal(limit); }else { limitPrice =price * Convert.ToDecimal(1/limit); } Log("Limit Order: "+ orderQuantity+ " coins @ $"+limitPrice+ " per coin"); LimitOrder(symbol, orderQuantity, limitPrice); } public override void OnData(Slice data) { foreach (StockData stockData in stockDatas) { stockData.history.Add(data[stockData.Ticker].Close); if (stockData.history.Count>historyLength) { stockData.history.RemoveAt(0); } if (stockData.history.Count>=2) { if (stockData.history[stockData.history.Count-2]!=0) { decimal change=(stockData.history.Last()-stockData.history[stockData.history.Count-2])/stockData.history[stockData.history.Count-2]; stockData.changes1History.Add(change); if (stockData.changes1History.Count>changes1Length) { stockData.changes1History.RemoveAt(0); } } } if (stockData.changes1History.Count>=2) { decimal change=stockData.changes1History.Last()-stockData.changes1History[stockData.changes1History.Count-2]; stockData.changes2History.Add(change); if (stockData.changes2History.Count>changes2Length) { stockData.changes2History.RemoveAt(0); } } if (stockData.changes1History.Count>0) { stockData.emaOfChanges1Indicator.Update(Time,stockData.changes1History.Last()); } if (stockData.changes2History.Count>0) { stockData.emaOfChanges2Indicator.Update(Time,stockData.changes2History.Last()); } stockData.Fitness=changes1Ratio*stockData.emaOfChanges1Indicator+changes2Ratio*stockData.emaOfChanges2Indicator; } var q1 = from x in stockDatas orderby x.Fitness descending select x; List<StockData> q2=q1.ToList(); if (q2.Count>0) { StockData selectedStockData=q2.First(); if (selectedStockData.Ticker != stockHeld) { Liquidate(); SetHoldings_(selectedStockData.Ticker, leverage); stockHeld=selectedStockData.Ticker; } } } class StockData { public string Ticker; public List<decimal> history=new List<decimal>(); public List<decimal> changes1History=new List<decimal>(); public List<decimal> changes2History=new List<decimal>(); public ExponentialMovingAverage emaOfChanges1Indicator; public ExponentialMovingAverage emaOfChanges2Indicator; public decimal Fitness; } } }