| Overall Statistics |
|
Total Trades 25 Average Win 0% Average Loss -1.16% Compounding Annual Return -81.842% Drawdown 13.500% Expectancy -1 Net Profit -13.489% Sharpe Ratio -2.753 Probabilistic Sharpe Ratio 0.321% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.107 Beta 0.008 Annual Standard Deviation 0.041 Annual Variance 0.002 Information Ratio 1.736 Tracking Error 0.381 Treynor Ratio -14.348 Total Fees $18603.56 Estimated Strategy Capacity $150000.00 Lowest Capacity Asset BTCUSD XJ |
#region imports
from AlgorithmImports import *
#endregion
# EMA Cross over strategy 9-13-21-55
# -------------------------------------------------------------------
CRYPTO = "BTCUSD"; EMA_C1 = 9; EMA_C2 = 13; EMA_F = 21; EMA_S = 55;
# -------------------------------------------------------------------
class MovingAverageCrossAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 4, 1)
self.SetEndDate(2022, 5, 1)
self.SetCash("USDT", 100000)
self.SetBrokerageModel(BrokerageName.FTXUS, AccountType.Margin)
res = Resolution.Hour
self.crypto = self.AddCrypto(CRYPTO, res, Market.GDAX).Symbol
self.ema_c1 = self.EMA(self.crypto, EMA_C1, res)
self.ema_c2 = self.EMA(self.crypto, EMA_C2, res)
self.ema_f = self.EMA(self.crypto, EMA_F, res)
self.ema_s = self.EMA(self.crypto, EMA_S, res)
self.SetWarmUp(5*EMA_S, res)
self.sell_Ticket = False
self.buy_Ticket = False
self.position_close_long = False
self.position_close_short = False
def OnData(self, data):
if self.IsWarmingUp:
return
if not self.ema_s.IsReady:
return
ema_c1 = self.ema_c1.Current.Value
ema_c2 = self.ema_c2.Current.Value
ema_f = self.ema_f.Current.Value
ema_s = self.ema_s.Current.Value
self.Plot(self.crypto, "Price", self.Securities[self.crypto].Price)
self.Plot(self.crypto, "ema_c1", ema_c1)
self.Plot(self.crypto, "ema_c2", ema_c2)
self.Plot(self.crypto, "ema_f", ema_f)
self.Plot(self.crypto, "ema_s", ema_s )
# open initial long when ema ribbon crosses to the upside
if not self.Portfolio[self.crypto].IsLong:
if not self.sell_Ticket:
if not self.position_close_long:
if self.ema_c1 > self.ema_c2 > self.ema_f > self.ema_s:
self.SetHoldings(self.crypto, 0.95)
self.sell_Ticket = True
# close long when the two fastest emas cross, create a boolan to keep track
if self.Portfolio[self.crypto].IsLong:
if self.sell_Ticket:
if ema_c1 < ema_c2:
self.Liquidate(self.crypto)
self.position_close_long = True
# reopen position if it was closed and it was a fake out
if not self.Portfolio[self.crypto].IsLong:
if self.sell_Ticket and self.position_close_long:
if ema_f < ema_c2 < ema_c1:
self.SetHoldings(self.crypto, 0.95)
self.position_close_long = False
# reset all boolans when ribbon flips
if not self.Portfolio[self.crypto].IsLong:
if self.position_close_long:
if ema_f < ema_s:
self.position_close_long = False
self.sell_ticket = False
## open initial short when ema ribbon crosses to the upside
if not self.Portfolio[self.crypto].IsShort:
if not self.buy_Ticket:
if not self.position_close_short:
if ema_c1 < ema_c2 < ema_f < ema_s:
self.SetHoldings(self.crypto, -0.95)
self.buy_Ticket = True
## close short when the two fastest emas cross, create a boolan to keep track
if self.Portfolio[self.crypto].IsShort:
if self.buy_Ticket:
if ema_c2 > ema_c1:
self.Liquidate(self.crypto)
self.position_close_short = True
## reopen short position if it was closed and it was a fake out
if not self.Portfolio[self.crypto].IsShort:
if self.buy_Ticket and self.position_close_short:
if self.ema_f > self.ema_c2 > self.ema_c1 :
self.SetHoldings(self.crypto, -0.95)
self.position_close_short = False
## reset all boolans when ribbon flips
if not self.Portfolio[self.crypto].IsShort:
if self.buy_Ticket and self.position_close_short:
if ema_s < ema_f:
self.position_close_short = False
self.buy_ticket = False