| 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;
}
}
}