Overall Statistics
Total Trades
1133
Average Win
0.92%
Average Loss
-0.63%
Compounding Annual Return
0.431%
Drawdown
23.600%
Expectancy
0.011
Net Profit
1.464%
Sharpe Ratio
0.08
Probabilistic Sharpe Ratio
2.097%
Loss Rate
59%
Win Rate
41%
Profit-Loss Ratio
1.45
Alpha
-0.012
Beta
0.224
Annual Standard Deviation
0.102
Annual Variance
0.01
Information Ratio
-0.443
Tracking Error
0.18
Treynor Ratio
0.037
Total Fees
$2061.48
Estimated Strategy Capacity
$19000000.00
Lowest Capacity Asset
QQQ RIWIV7K5Z9LX
Portfolio Turnover
86.82%
# region imports
from AlgorithmImports import *
# endregion

class MuscularTanMosquito(QCAlgorithm):

    # In raw price diff
    # sl = .25
    sl_dlrs = 200 #DEFAULT -- overridden by the left hand pane.
    ticker = 'QQQ'

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        self.symbol = self.AddEquity(self.ticker, Resolution.Minute).Symbol

        # Required for options...
        # self.Securities[self.symbol].SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        self.Schedule.On(self.DateRules.EveryDay(self.symbol),
                 self.TimeRules.BeforeMarketClose(self.symbol, 10),
                 self.EOD)
    
        self.open_d = None 
        self.high_d = 0
        self.high_d1 = None 

        # PARAMETERS (actual)

        tst = self.GetParameter("SL")
        if tst: 
            self.sl_dlrs = int(tst)

    def EOD(self):
        invested = [kvp.Key for kvp in self.Portfolio if kvp.Value.Invested]
        for symbol in invested:
            opnl = self.Portfolio[symbol].UnrealizedProfit
            self.Liquidate(symbol, f"EOD Exit -- PNL {opnl}")

    def OnData(self, data: Slice):

        data = data.Bars 
        if not data.ContainsKey(self.symbol): return 

        o,h,l,c = data[self.symbol].Open, data[self.symbol].High, data[self.symbol].Low, data[self.symbol].Close
        bar_tm = data[self.symbol].EndTime

        # self.Debug(f'Bar Time: {bar_tm}')
        if bar_tm.hour == 9 and bar_tm.minute == 31:
            self.open_d = o
            self.high_d1 = self.high_d
            self.high_d = h

            # Use historical lookup instead...
            hist = self.History(self.symbol, 5, Resolution.Daily).loc[self.symbol]
            self.high_d1 = hist.iloc[-1].high
            self.Debug(f'{self.Time} -- open > high[1] ? {self.open_d} > {self.high_d1}')

        
        self.high_d = max(h, self.high_d)

        if all([self.high_d, self.high_d1]):
            if self.EntryLogic:
                if not self.Portfolio.Invested:
                    quantity = self.CalculateOrderQuantity(self.symbol, 0.95)
                    self.MarketOrder(self.symbol, quantity, False, "Entry")


    @property
    def EntryLogic(self):
        return self.open_d > self.high_d1
        ## TODO: use  OnOrderEvent to set stop? 


    def OnOrderEvent(self, orderEvent):
        #ONLY concerned with FILLED orders. Wait on partials, etc.
        if orderEvent.Status != OrderStatus.Filled:
            return
                
        order_symbol = orderEvent.Symbol
        
        oid = orderEvent.OrderId
        order = self.Transactions.GetOrderById(oid)
        shares = orderEvent.AbsoluteFillQuantity
        entry_price = orderEvent.FillPrice 
        
        dir = orderEvent.Direction

        buy = dir == OrderDirection.Buy
        sell = dir == OrderDirection.Sell
        
        fill_price = orderEvent.FillPrice   

        entry = order.Tag.startswith("Entry")
        exit = order.Tag.startswith("SSL") or order.Tag.startswith("LSL")
        if entry:
            if buy:
                sl_pts = abs(self.sl_dlrs / shares)  
                self.StopMarketOrder(order_symbol, -1 * shares, entry_price - sl_pts, "LSL")
            
            # if sell:
            #     self.StopMarketOrder(order_symbol, -1 * shares, entry_price + self.sl, "SSL")

            return 
        
        if exit:
            self.Transactions.CancelOpenOrders()