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