Overall Statistics
Total Trades
38
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$603.56
Estimated Strategy Capacity
$29000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
import numpy as np
import datetime


class GeekyFluorescentPinkFalcon(QCAlgorithm):

    def Initialize(self):
        
        # set up
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2020, 1, 2)
        self.SetCash(1000000)
        self.SetBenchmark("SPY")
        
        # data
        equity = self.AddEquity("SPY", Resolution.Minute)
        self.symbol = equity.Symbol
        self.Consolidate(self.symbol, timedelta(hours=4), self.FourHourBarHandler)
        self.Consolidate(self.symbol, Calendar.Weekly, self.WeeklyBarHandler)
        
        # parameters
        self.high_low_ratio = 1/2
        self.high_open_ratio = 0.1
        
        # init
        self.high_open_distance = False
        self.cond_1 = False
        self.cond_2 = False
        self.cond_retracement = False
        self.low_minute = 0
        self.open_minute = 0
        self.high_minute = 0
        self.open_low_mean = None
        self.open_high_mean = None  # mean of Open - High difference on 4H bar, window 100 
        self.rolling_high = RollingWindow[float](100)
        self.rolling_low = RollingWindow[float](100)
        self.rolling_open = RollingWindow[float](100)
        
        # warm up
        history = self.History([self.symbol], 100 * 5, Resolution.Hour)
        for index, row in history.loc[self.symbol].iterrows():
            self.rolling_high.Add(row.high)
            self.rolling_low.Add(row.low)
            self.rolling_open.Add(row.open)
        self.SetWarmup(100 * 4 * 60)
        
    # 4H Bar    
    def FourHourBarHandler(self, consolidated):

        # reset
        self.low_minute = 0
        self.open_minute == 0
        self.high_minute == 0
        self.cond_retracement = False
        self.cond_2 = False
        self.cond_1 = False

        # add data to rolling windows
        self.rolling_high.Add(consolidated.High)
        self.rolling_low.Add(consolidated.Low)
        self.rolling_open.Add(consolidated.Open)
        
        # check
        if not self.rolling_high.IsReady: return
        if not self.rolling_low.IsReady: return
        if not self.rolling_open.IsReady: return
    
        # mean of high - open diff
        high_open = np.array(list(self.rolling_high)) - np.array(list(self.rolling_open ))
        self.open_high_mean = np.mean(high_open)
        
        # mean of open - low diff
        open_low = np.array(list(self.rolling_open)) - np.array(list(self.rolling_low))
        self.open_low_mean = np.mean(open_low)
        
        # PROSJEK na 4H
        # self.high_open_distance = (consolidated.High - consolidated.Open) < (high_open_mean * self.high_low_ratio) MINUTNOJ
        
        # condition 1
        # self.high_open_distance = (consolidated.High - consolidated.Open) < (high_open_mean * self.high_low_ratio)
        # self.cond_2 = (consolidated.Open - consolidated.Low) > open_low_mean
        
        # self.Debug(f"time {self.Time}, high_open_distance {self.high_open_distance}, cond_2 {self.cond_2}")
        

    def OnOrderEvent(self, orderEvent):
        
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        
        if order.Status == OrderStatus.Filled:
            if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket: # or order.Type == OrderType.MarketOnOpen:
                self.Transactions.CancelOpenOrders(order.Symbol)

    def WeeklyBarHandler(self, consolidated):
        pass
        # self.Debug(f"{consolidated.EndTime},>> WeeklyBarHandler >> {consolidated.Close}")
        
    # Miutni barovi
    def OnData(self, data):

        # # time restriction
        # if self.Time.date < datetime.date(2020, 1, 1):
        #     return

        # check for data
        if not data.Bars.ContainsKey(self.symbol): return
        if not data.ContainsKey(self.symbol): return
        if data[self.symbol] is None: return 
        
        # check
        if self.open_low_mean is None:
            return
        
        # set open 4H
        self.Debug(f"Open: {self.open_minute}")
        if self.open_minute == 0:
           self.open_minute = data[self.symbol].Open 
        self.Debug(f"Open2: {self.open_minute}")
        self.Debug(f"Close: {data[self.symbol].Close}")
        
        # set low 4H
        if self.low_minute == 0:
            self.low_minute = data[self.symbol].Low
        elif data[self.symbol].Low < self.low_minute:
            self.low_minute = data[self.symbol].Low

        # set high 4H
        if self.high_minute == 0:
            self.high_minute = data[self.symbol].High
        elif data[self.symbol].High > self.high_minute:
            self.high_minute = data[self.symbol].High
        
        # condition 1: High - Open < mean(High - Open) * 0.01
        # self.cond_1 = self.high_minute - self.open_minute < (self.open_high_mean * self.high_open_ratio) # old way
        self.cond_1 = self.high_minute < self.rolling_high[0]
         
        # cond 2
        if self.cond_2 == False:
            self.cond_2 = (self.open_minute - self.low_minute) > self.open_low_mean

        # # 4H
        # self.rolling_high
        
        # # 1M
        # data[self.symbol].High
        # data[self.symbol].Low
        
        # # 1M with 4H reset
        # self.low_minute
        # self.high_minute

        # retracement
        if self.cond_retracement == False and self.cond_1 and self.cond_2:
            self.cond_retracement = (data[self.symbol].High - self.low_minute) > (self.open_minute - self.low_minute) * 0.4
            # if self.cond_retracement:
            #     self.Debug("Retracement")

        # order
        if not self.Portfolio[self.symbol].Invested and not self.Portfolio[self.symbol].IsLong:
            
            # DEBUG
            self.Debug(f"time {self.Time}, high_minute: {self.high_minute}, open_minute: {self.open_minute}")
            
            quantity = self.CalculateOrderQuantity(self.symbol, 1)
            self.MarketOrder(self.symbol, -quantity, tag = "Buy!")
            self.LimitOrder(self.symbol, quantity, self.low_minute)         # Profit take (PT, TP)
            self.StopMarketOrder(self.symbol, quantity, self.high_minute)   # Stop loss (SL)


# 3 uvjeta:
#     1) High - Open < mean(High - Open) * 0.01
#     2) (Open - Low)_t > (Open - Low) * 3/4
#     3) retrace: High - Low > 0.4 * (open - low),           High_t > (Open - Low)_t