Overall Statistics
Total Trades
22
Average Win
1.79%
Average Loss
-6.00%
Compounding Annual Return
-100.000%
Drawdown
74.700%
Expectancy
-0.900
Net Profit
-53.780%
Sharpe Ratio
-0.383
Probabilistic Sharpe Ratio
18.846%
Loss Rate
92%
Win Rate
8%
Profit-Loss Ratio
0.30
Alpha
-0.827
Beta
0.863
Annual Standard Deviation
2.608
Annual Variance
6.803
Information Ratio
-0.308
Tracking Error
2.599
Treynor Ratio
-1.156
Total Fees
$62.90
Estimated Strategy Capacity
$130000000.00
Lowest Capacity Asset
CL XYME7AM671S1
# CrudeOilWTI TrueRange

from datetime import timedelta
from collections import deque


class LogicalBrownKoala(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2022, 4, 15)
        self.SetCash(100000)
        future = self.AddFuture(Futures.Energies.CrudeOilWTI, Resolution.Minute)
        future.SetFilter(timedelta(10), timedelta(180))

        self.slow_sma = None
        self.slow_sma_period = 25
        self.fast_sma = None
        self.fast_sma_period = 12
        self.CCIPeriod = 30 
        self.CCIupperBound = 100 
        self.CCIlowerBound = -100 
        self.volume_sma_period = 30
        self.consolidator_by_symbol = {}
        
        
    def OnData(self, slice):

        stop_time_start = self.Time.replace(hour=15, minute=00)
        stop_time_end = self.Time.replace(hour=16, minute=30)
        if self.Time > stop_time_end or self.Time < stop_time_start:
            return
        
        for chain in slice.FutureChains.Values:
            contracts = chain.Contracts
            if len(contracts) == 0:
                continue
            sorted_by_oi_contracts = sorted(contracts.Values, key=lambda k: k.OpenInterest, reverse=True)
            popular_contract = sorted_by_oi_contracts[0]

            if popular_contract.Symbol not in self.consolidator_by_symbol:
                Consolidator = TradeBarConsolidator(timedelta(minutes=3))
                self.consolidator_by_symbol[popular_contract.Symbol] = Consolidator
                
                self.slow_sma = LinearWeightedMovingAverage(self.slow_sma_period)
                self.RegisterIndicator(popular_contract.Symbol, self.slow_sma, Consolidator)

                self.fast_sma = LinearWeightedMovingAverage(self.fast_sma_period)
                self.RegisterIndicator(popular_contract.Symbol, self.fast_sma, Consolidator)

                self.volume_sma = LinearWeightedMovingAverage(self.fast_sma_period)
                self.RegisterIndicator(popular_contract.Symbol, self.volume_sma, Consolidator, Field.Volume)

                self.cci = self.CCI(popular_contract.Symbol, self.CCIPeriod,  MovingAverageType.Simple, Resolution.Daily)
                self.RegisterIndicator(popular_contract.Symbol, self.cci, Consolidator)

                self.true_range = True_Range("TrueRange", 2)
                self.RegisterIndicator(popular_contract.Symbol, self.true_range, Consolidator)

            self.Plot("Indicator", "TrueRange", self.true_range.Current.Value)    
            '''
            self.Plot("Indicator", "SMA slow", self.slow_sma.Current.Value)
            self.Plot("Indicator", "SMA fast", self.fast_sma.Current.Value)
            self.Plot("Indicator 2", "SMA Volume", self.volume_sma.Current.Value)
            self.Plot("CCI", "CCI value", self.cci.Current.Value)
            '''
            
            if self.slow_sma.Current.Value > self.fast_sma.Current.Value:
                self.SetHoldings(popular_contract.Symbol, 1)
                
                
class True_Range(PythonIndicator):

    def __init__(self, name, period):
        self.Name = name
        self.Value = None
        self.period = period
        self.WarmUpPeriod = period
        self.Time = datetime.min
        self.queue_close = deque(maxlen=period)
        self.queueTime = deque(maxlen=period)
    
    def Update(self, input):
        self.queue_close.appendleft(input.Close)
        self.queueTime.appendleft(input.EndTime)
        self.Time = input.EndTime
        count = len(self.queue_close)

        if self.queue_close[0] > input.High: 
            TH = self.queue_close[0]
        else:
            TH = input.High
        if self.queue_close[0] < input.Low: 
            TL = self.queue_close[0]
        else: 
            TL = input.Low
        self.Value = TH - TL

        self.IsReady == self.queue_close.maxlen
        return self.IsReady