| Overall Statistics |
|
Total Trades 38 Average Win 1.93% Average Loss -1.18% Compounding Annual Return -15.861% Drawdown 13.500% Expectancy -0.584 Net Profit -12.434% Sharpe Ratio -2.072 Probabilistic Sharpe Ratio 0.076% Loss Rate 84% Win Rate 16% Profit-Loss Ratio 1.63 Alpha -0.172 Beta 0.093 Annual Standard Deviation 0.075 Annual Variance 0.006 Information Ratio -0.963 Tracking Error 0.343 Treynor Ratio -1.675 Total Fees $49.50 |
class experiment1(QCAlgorithm):
def CreateBracketOrder(self, ticker, posSize, entry, limit, sl, pt, risk):
return experiment1.bracket(self, ticker, posSize, entry, limit, sl, pt, risk)
class bracket:
def __init__(self, outer, ticker, posSize, entry, limit, sl, pt, risk):
self.outer = outer
self.ticker = ticker
self.posSize = posSize
self.entry = entry
self.sl = sl
self.pt = pt
self.risk = risk
self.entryTix = self.outer.StopLimitOrder(ticker, posSize, entry, limit)
self.slTix = None
self.ptTix = None
self.entryTime = None
def getExits(self):
return [
self.slTix.OrderId if self.slTix is not None else None,
self.ptTix.OrderId if self.ptTix is not None else None,
]
def createExits(self):
self.outer.Log(f"buy {self.posSize} {self.ticker} at {self.entry}")
self.entryTime = self.outer.Time
self.slTix = self.outer.StopMarketOrder(self.ticker, -self.posSize, self.sl)
self.ptTix = self.outer.LimitOrder(self.ticker, -self.posSize, self.pt)
def cancelExits(self, orderID):
if orderID == self.slTix.OrderId:
self.outer.Log(f"sl {self.posSize} {self.ticker} at {self.sl}")
self.ptTix.Cancel()
else:
self.outer.Log(f"pt {self.posSize} {self.ticker} at {self.pt}")
self.slTix.Cancel()
def Initialize(self):
self.SetStartDate(2020, 1, 1) # Set Start Date
self.SetCash(10000) # Set Strategy Cash
self.openOrders = {}
self.orderPrecision = 2
# self.UniverseSettings.Resolution = Resolution.Hour
# self.UniverseSettings.Leverage = 1
# self.AddUniverse(self.CoarseSelectionFilter)
self.tmp = self.AddEquity("GE", Resolution.Hour)
self.tmp.SetDataNormalizationMode(DataNormalizationMode.Raw)
# def CoarseSelectionFilter(self, coarse):
# sortedByDollarVolume = sorted(
# coarse, key=lambda x: x.DollarVolume, reverse=True
# )
# filtered = [
# x.Symbol
# for x in sortedByDollarVolume
# if x.Price > 10 and x.DollarVolume > 10000000
# ][:10]
# self.Debug(str(len(filtered)))
# return filtered
# def OnSecuritiesChanged(self, changes):
# self.Debug(f"{self.Time.date()} {self.Time.hour} {self.Time.minute}")
def OnData(self, data):
# risk 1% of portfolio per trade
# risk per share = entry - stop loss
# pos size = 1% portfolio / risk per share
if "GE" not in self.openOrders:
entry = round(self.Securities["GE"].Close, self.orderPrecision)
limit = round(entry * 1.001, self.orderPrecision)
sl = round(entry * 0.95, self.orderPrecision)
risk = round(entry - sl, self.orderPrecision)
pt = round(entry + 2 * risk, self.orderPrecision)
posSize = int((self.Portfolio.TotalPortfolioValue * 0.01) / risk)
self.openOrders["GE"] = self.CreateBracketOrder(
"GE", posSize, entry, limit, sl, pt, risk
)
# self.Debug("{} {}".format(self.Portfolio.Cash, self.Portfolio.TotalPortfolioValue))
# self.Debug("{} {} {} {} {}".format(entry, risk, sl, pt, risk, posSize))
for k, v in self.openOrders.items():
if (
v.entryTime is not None
and (self.Time - v.entryTime).days > 2
and v.slTix.Get(OrderField.StopPrice) < v.entry
and self.Securities[v.ticker].Close > v.entry + 0.5 * v.risk
):
# pass
self.Debug(
f"updating SL from {v.slTix.Get(OrderField.StopPrice)} to {v.entry}."
)
v.slTix.UpdateStopPrice(v.entry)
def OnOrderEvent(self, orderevent):
if orderevent.Status == OrderStatus.UpdateSubmitted:
tmp = self.openOrders["GE"].slTix.Get(OrderField.StopPrice)
self.Debug(f"SL update submitted: {tmp} ")
if orderevent.Status != OrderStatus.Filled:
return
# handle OCO orders
for k, v in self.openOrders.items():
if orderevent.OrderId == v.entryTix.OrderId:
v.createExits()
elif orderevent.OrderId in v.getExits():
v.cancelExits(orderevent.OrderId)
self.openOrders.pop(k)
break