Overall Statistics
Total Trades
110502
Average Win
0.04%
Average Loss
-0.03%
Compounding Annual Return
56.068%
Drawdown
12.900%
Expectancy
0.266
Net Profit
13310.821%
Sharpe Ratio
3.039
Probabilistic Sharpe Ratio
100.000%
Loss Rate
46%
Win Rate
54%
Profit-Loss Ratio
1.33
Alpha
0.37
Beta
-0.004
Annual Standard Deviation
0.122
Annual Variance
0.015
Information Ratio
1.455
Tracking Error
0.187
Treynor Ratio
-87.083
Total Fees
$19067188.56
Estimated Strategy Capacity
$0
Lowest Capacity Asset
ARBZERO.ArbZeroArbSpreadProvider 2S
Portfolio Turnover
4.03%
#region imports
from AlgorithmImports import *
#endregion


class Strategy:

    def __init__(self, algo: QCAlgorithm):
        self.algo = algo
        self.contract = None
        self.position = 0

        pass

    @property
    def GetPosition(self):
        return self.position


    def CreateSignals(self):
        pass
#region imports
from AlgorithmImports import *
from data_utils import ArbSymbols
#endregion

symbols = ArbSymbols()

def GetArbSpreadProvider(symbol):

    links = {
        symbols.ThreeMonthArbZero:  'https://www.dropbox.com/s/dzq3yqsmsn91mn8/Arb_3_Month_Zero.csv?dl=1',
        symbols.ThreeMonthArbOne:  'https://www.dropbox.com/s/3itjrhue557gb3i/Arb_3_Month_One.csv?dl=1',
        symbols.ThreeMonthArbTwo:  'https://www.dropbox.com/s/jgp2obuzhl4jggz/Arb_3_Month_Two.csv?dl=1',
        symbols.ThreeMonthArbThree:  'https://www.dropbox.com/s/kpvfzb1xkxzq24q/Arb_3_Month_Three.csv?dl=1',
        symbols.SixMonthArbZero:  'https://www.dropbox.com/s/m915m8v9l1c7zdx/Arb_6_Month_Zero.csv?dl=1',
        symbols.SixMonthArbOne:  'https://www.dropbox.com/s/mxssnc1xihfm7v3/Arb_6_Month_One.csv?dl=1',
        symbols.SixMonthArbTwo:  'https://www.dropbox.com/s/1vi3ox7s90142yk/Arb_6_Month_Two.csv?dl=1',
        symbols.SixMonthArbThree:  'https://www.dropbox.com/s/0l90fqa4j0jihrg/Arb_6_Month_Three.csv?dl=1',
        symbols.ArbZero: 'https://www.dropbox.com/s/v163dgvtbef6nfe/Arb_Spread_0.csv?dl=1',
        symbols.ArbOne: 'https://www.dropbox.com/s/mg3z7smxov0yilb/Arb_Spread_1.csv?dl=1',
        symbols.ArbTwo: 'https://www.dropbox.com/s/cp1w8gk340svi43/Arb_Spread_2.csv?dl=1',
        symbols.ArbThree: 'https://www.dropbox.com/s/vny7csw2sdcvu5x/Arb_Spread_3.csv?dl=1',
    }

    class ArbSpreadProvider(PythonData):

        def GetSource(self,
            config: SubscriptionDataConfig,
            date: datetime,
            isLive: bool) -> SubscriptionDataSource:
            return SubscriptionDataSource(links[symbol], SubscriptionTransportMedium.RemoteFile)

        def Reader(self,
            config: SubscriptionDataConfig,
            line: str,
            date: datetime,
            isLive: bool) -> BaseData:

            if not (line.strip()):
                return None

            index = ArbSpreadProvider()
            index.Symbol = config.Symbol

            try:
                data = line.split(',')
                index.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S')
                index.EndTime = index.Time + timedelta(minutes=1)
                index.Value = data[4]
                index["open"] = float(data[1])
                index["high"] = float(data[2])
                index["low"] = float(data[3])
                index["close"] = float(data[4])
                index['volume'] = float(data[5])

            except ValueError:
                # Do nothing
                return None

            return index


    def GetSource(self,
         config: SubscriptionDataConfig,
         date: datetime,
         isLive: bool) -> SubscriptionDataSource:
        return SubscriptionDataSource(links['offset_3'], SubscriptionTransportMedium.RemoteFile)

    def Reader(self,
         config: SubscriptionDataConfig,
         line: str,
         date: datetime,
         isLive: bool) -> BaseData:

        if not (line.strip()):
            return None

        index = ArbSpreadOffsetThree()
        index.Symbol = config.Symbol

        try:
            data = line.split(',')
            index.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S')
            index.EndTime = index.Time + timedelta(minutes=1)
            index.Value = data[4]
            index["open"] = float(data[1])
            index["high"] = float(data[2])
            index["low"] = float(data[3])
            index["close"] = float(data[4])
            index['volume'] = float(data[5])

        except ValueError:
            # Do nothing
            return None

        return index
    ArbSpreadProvider.__qualname__ = f'{symbol}{ArbSpreadProvider.__name__}'

    return ArbSpreadProvider
#region imports
from AlgorithmImports import *
from data_utils import SpreadSymbols, ArbSymbols, OutrightSymbols, DataInitialiser
from data.Spreads import GetSpreadProvider
from data.Outrights import GetOutrightProvider
from data.Arbs import GetArbSpreadProvider
from reality_modelling.fees import *
#endregion


class DataProviders():

    SPREADS = {
        # CL
        SpreadSymbols().CLThreeMonthZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLThreeMonthZero), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLThreeMonthOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLThreeMonthOne), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLThreeMonthTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLThreeMonthTwo), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLThreeMonthThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLThreeMonthThree), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSixMonthZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSixMonthZero), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSixMonthOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSixMonthOne), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSixMonthTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSixMonthTwo), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSixMonthThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSixMonthThree), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadZero), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadOne), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadTwo), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadThree), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadThreeMonthZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadThreeMonthZeroDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadThreeMonthOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadThreeMonthOneDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadThreeMonthTwoDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadThreeMonthTwoDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadThreeMonthThreeDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadThreeMonthThreeDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadSixMonthZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadSixMonthZeroDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadSixMonthOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadSixMonthOneDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadSixMonthTwoDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadSixMonthTwoDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadSixMonthThreeDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadSixMonthThreeDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadZeroDivision), 
            feeModel=CLSpreadFeeModel
            ),
        SpreadSymbols().CLSpreadOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().CLSpreadOneDivision), 
            feeModel=CLSpreadFeeModel
            ),
        # Brent 
        SpreadSymbols().BRThreeMonthZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRThreeMonthZero), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRThreeMonthOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRThreeMonthOne), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRThreeMonthTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRThreeMonthTwo), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRThreeMonthThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRThreeMonthThree), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSixMonthZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSixMonthZero), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSixMonthOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSixMonthOne), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSixMonthTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSixMonthTwo), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSixMonthThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSixMonthThree), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadZero: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadZero), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadOne: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadOne), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadTwo: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadTwo), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadThree: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadThree), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadThreeMonthZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadThreeMonthZeroDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadThreeMonthOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadThreeMonthOneDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadThreeMonthTwoDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadThreeMonthTwoDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadThreeMonthThreeDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadThreeMonthThreeDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadSixMonthZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadSixMonthZeroDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadSixMonthOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadSixMonthOneDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadSixMonthTwoDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadSixMonthTwoDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadSixMonthThreeDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadSixMonthThreeDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadZeroDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadZeroDivision), 
            feeModel=BRSpreadFeeModel
            ),
        SpreadSymbols().BRSpreadOneDivision: DataInitialiser(
            GetSpreadProvider(SpreadSymbols().BRSpreadOneDivision), 
            feeModel=BRSpreadFeeModel
            ),
    }

    ARBS = {
        ArbSymbols().ThreeMonthArbZero: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ThreeMonthArbZero),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ThreeMonthArbOne: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ThreeMonthArbOne),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ThreeMonthArbTwo: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ThreeMonthArbTwo),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ThreeMonthArbThree: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ThreeMonthArbThree),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().SixMonthArbZero: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().SixMonthArbZero),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().SixMonthArbOne: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().SixMonthArbOne),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().SixMonthArbTwo: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().SixMonthArbTwo),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().SixMonthArbThree: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().SixMonthArbThree),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ArbZero: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ArbZero),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ArbOne: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ArbOne),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ArbTwo: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ArbTwo),
            feeModel=ArbSpreadFeeModel
            ),
        ArbSymbols().ArbThree: DataInitialiser(
            GetArbSpreadProvider(ArbSymbols().ArbThree),
            feeModel=ArbSpreadFeeModel
            ),
    }

    OUTRIGHTS = {
        OutrightSymbols().CL: DataInitialiser(
            GetOutrightProvider(OutrightSymbols().CL),
            feeModel=ClOutrightFeeModel
        ),
        OutrightSymbols().BR: DataInitialiser(
            GetOutrightProvider(OutrightSymbols().BR),
            feeModel=BrOutrightFeeModel
        )
    }
#region imports
from AlgorithmImports import *
from DataProviders import DataProviders
#endregion

class ManageData(DataProviders):

    def __init__(self, algo: QCAlgorithm, 
        spreads = { key: False for key in DataProviders().SPREADS.keys() }, 
        arbs = { key: False for key in DataProviders().ARBS.keys() }, 
        outrights = { key: False for key in DataProviders().OUTRIGHTS.keys() }
        ):

        self.data = {}

        # Setup Spreads Data
        for key, value in spreads.items():
            if value:
                data = algo.AddData(
                    self.SPREADS[key].PROVIDER, 
                    key,
                    properties=SymbolProperties(
                        description = f'{key} Spread', 
                        quoteCurrency = 'USD', 
                        contractMultiplier = 1000.0, 
                        minimumPriceVariation = 0.01, 
                        lotSize = 1.0, 
                        marketTicker = key
                    ),
                    exchangeHours=SecurityExchangeHours.AlwaysOpen(TimeZones.Utc)
                    )
                data.SetFeeModel(self.SPREADS[key].FEE_MODEL())
                data.SetFillModel(FutureFillModel())
                data.SetBuyingPowerModel(FutureMarginModel())
                self.data[key] = data


        # Setup Arbs Data
        for key, value in arbs.items():
            if value:
                data = algo.AddData(
                    self.ARBS[key].PROVIDER,
                    key,
                    properties=SymbolProperties(
                        description = f'{key} Arb', 
                        quoteCurrency = 'USD', 
                        contractMultiplier = 1000.0, 
                        minimumPriceVariation = 0.01, 
                        lotSize = 1.0, 
                        marketTicker = key
                    ),
                    exchangeHours=SecurityExchangeHours.AlwaysOpen(TimeZones.Utc)
                    )
                data.SetFeeModel(self.ARBS[key].FEE_MODEL())
                data.SetFillModel(FutureFillModel())
                data.SetBuyingPowerModel(FutureMarginModel())
                self.data[key] = data

        # Setup Outrights Data
        for key, value in outrights.items():
            if value:
                data = algo.AddData(
                    self.OUTRIGHTS[key].PROVIDER,
                    key,
                    properties=SymbolProperties(
                        description = f'{key} Outright', 
                        quoteCurrency = 'USD', 
                        contractMultiplier = 1000.0, 
                        minimumPriceVariation = 0.01, 
                        lotSize = 1.0, 
                        marketTicker = key
                    ),
                    exchangeHours=SecurityExchangeHours.AlwaysOpen(TimeZones.Utc)
                    )
                data.SetFeeModel(self.OUTRIGHTS[key].FEE_MODEL())
                data.SetFillModel(FutureFillModel())
                data.SetBuyingPowerModel(FutureMarginModel())
                self.data[key] = data
#region imports
from AlgorithmImports import *
from data_utils import OutrightSymbols
#endregion

symbols = OutrightSymbols()

def GetOutrightProvider(symbol):

    links = {
        symbols.CL: 'https://www.dropbox.com/s/3l0boaibz74sod1/CL_continuous.csv?dl=1',
        symbols.BR: 'https://www.dropbox.com/s/zu88jbs326blw52/BR_continuous.csv?dl=1'
    }

    class ContinuousFutures(PythonData):

        def GetSource(self,
            config: SubscriptionDataConfig,
            date: datetime,
            isLive: bool) -> SubscriptionDataSource:
            return SubscriptionDataSource(links[symbol], SubscriptionTransportMedium.RemoteFile)

        def Reader(self,
            config: SubscriptionDataConfig,
            line: str,
            date: datetime,
            isLive: bool) -> BaseData:

            if not (line.strip()):
                return None

            index = ContinuousFutures()
            index.Symbol = config.Symbol

            try:
                data = line.split(',')
                index.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S')
                index.EndTime = index.Time + timedelta(minutes=1)
                index.Value = data[4]
                index["open"] = float(data[1])
                index["high"] = float(data[2])
                index["low"] = float(data[3])
                index["close"] = float(data[4])
                index['volume'] = int(data[5])

            except ValueError:
                # Do nothing
                return None

            return index

    ContinuousFutures.__qualname__ = f'{symbol}{ContinuousFutures.__name__}'

    return ContinuousFutures
#region imports
from AlgorithmImports import *
from data.data_utils import SpreadSymbols
#endregion

symbols = SpreadSymbols()

def GetSpreadProvider(symbol):

    links = {
        symbols.CLThreeMonthZero: 'https://www.dropbox.com/s/boufkdh8vzo7ie5/CL_3_Month_Zero.csv?dl=1',
        symbols.CLThreeMonthOne: 'https://www.dropbox.com/s/2sk8q7u19y0t5j2/CL_3_Month_One.csv?dl=1',
        symbols.CLThreeMonthTwo: 'https://www.dropbox.com/s/8szed0ijrfg6nbu/CL_3_Month_Two.csv?dl=1',
        symbols.CLThreeMonthThree: 'https://www.dropbox.com/s/25yr0ctjozqivmx/CL_3_Month_Three.csv?dl=1',

        symbols.CLSixMonthZero: 'https://www.dropbox.com/s/u86wtwnj2xccx33/CL_6_Month_Zero.csv?dl=1',
        symbols.CLSixMonthOne: 'https://www.dropbox.com/s/n6bg80v2a0g9omx/CL_6_Month_One.csv?dl=1',
        symbols.CLSixMonthTwo: 'https://www.dropbox.com/s/l3p1mbidu28xko8/CL_6_Month_Two.csv?dl=1',
        symbols.CLSixMonthThree: 'https://www.dropbox.com/s/u6610g0immcyxuz/CL_6_Month_Three.csv?dl=1',

        symbols.CLSpreadZero: 'https://www.dropbox.com/s/5uvhz1hjftkensm/CL_Calendar_0.csv?dl=1',
        symbols.CLSpreadOne: 'https://www.dropbox.com/s/si4v5y8glpat510/CL_Calendar_1.csv?dl=1',
        symbols.CLSpreadTwo: 'https://www.dropbox.com/s/fhaxuj45h1i44uf/CL_Calendar_2.csv?dl=1',
        symbols.CLSpreadThree: 'https://www.dropbox.com/s/rplv7jdyh1kq4h5/CL_Calendar_3.csv?dl=1',

        symbols.CLSpreadThreeMonthZeroDivision: 'https://www.dropbox.com/s/ijv94wmx9xs13zq/CL_3_Month_Zero_Div.csv?dl=1',
        symbols.CLSpreadThreeMonthOneDivision: 'https://www.dropbox.com/s/2q9of4zzwtevaw4/CL_3_Month_One_Div.csv?dl=1',
        symbols.CLSpreadThreeMonthTwoDivision: 'https://www.dropbox.com/s/ynf3ul602x7sqmp/CL_3_Month_Two_Div.csv?dl=1',
        symbols.CLSpreadThreeMonthThreeDivision: 'https://www.dropbox.com/s/65nnymnt7ez2ewk/CL_3_Month_Three_Div.csv?dl=1',

        symbols.CLSpreadSixMonthZeroDivision: 'https://www.dropbox.com/s/imxfzsumn53gv4k/CL_6_Month_Zero_Div.csv?dl=1',
        symbols.CLSpreadSixMonthOneDivision: 'https://www.dropbox.com/s/nbpi5twrnhjh2jx/CL_6_Month_One_Div.csv?dl=1',
        symbols.CLSpreadSixMonthTwoDivision: 'https://www.dropbox.com/s/6cveld2rdewyu39/CL_6_Month_Two_Div.csv?dl=1',
        symbols.CLSpreadSixMonthThreeDivision: 'https://www.dropbox.com/s/fdv9tp05e6x913n/CL_6_Month_Three_Div.csv?dl=1',

        symbols.CLSpreadZeroDivision: 'https://www.dropbox.com/s/u6klq8rwvdsc9dh/CL_0_Year_Offset_div.csv?dl=1',
        symbols.CLSpreadOneDivision: 'https://www.dropbox.com/s/jv4i7k5hszai8yd/CL_1_Year_Offset_div.csv?dl=1',

        symbols.BRThreeMonthZero: 'https://www.dropbox.com/s/gj3l9reu9amacw5/BR_3_Month_Zero.csv?dl=1',
        symbols.BRThreeMonthOne: 'https://www.dropbox.com/s/krcz5fl0b3hqx68/BR_3_Month_One.csv?dl=1',
        symbols.BRThreeMonthTwo: 'https://www.dropbox.com/s/3gon5383s7dn93p/BR_3_Month_Two.csv?dl=1',
        symbols.BRThreeMonthThree: 'https://www.dropbox.com/s/tm93d8od3bmonjz/BR_3_Month_Three.csv?dl=1',

        symbols.BRSixMonthZero: 'https://www.dropbox.com/s/cp6nfacr70wy2w3/BR_6_Month_Zero.csv?dl=1',
        symbols.BRSixMonthOne: 'https://www.dropbox.com/s/lb26o1cxmtwyazb/BR_6_Month_One.csv?dl=1',
        symbols.BRSixMonthTwo: 'https://www.dropbox.com/s/9q78wmw0tus5exy/BR_6_Month_Two.csv?dl=1',
        symbols.BRSixMonthThree: 'https://www.dropbox.com/s/wf0o4woyddigo3z/BR_6_Month_Three.csv?dl=1',

        symbols.BRSpreadZero: 'https://www.dropbox.com/s/oh8itb8hmh3br6h/BR_Calendar_0.csv?dl=1',
        symbols.BRSpreadOne: 'https://www.dropbox.com/s/xzcanpz4sesaayt/BR_Calendar_1.csv?dl=1',
        symbols.BRSpreadTwo: 'https://www.dropbox.com/s/4x42yb6aum6gzsf/BR_Calendar_2.csv?dl=1',
        symbols.BRSpreadThree: 'https://www.dropbox.com/s/vzt0pjqe7s5dsfm/BR_Calendar_3.csv?dl=1',

        symbols.BRSpreadThreeMonthZeroDivision: 'https://www.dropbox.com/s/thx51l36593lvfd/BR_3_Month_Zero_Div.csv?dl=1',
        symbols.BRSpreadThreeMonthOneDivision: 'https://www.dropbox.com/s/a8mg17c5xcoa0eq/BR_3_Month_One_Div.csv?dl=1',
        symbols.BRSpreadThreeMonthTwoDivision: 'https://www.dropbox.com/s/mg9o60x6uh8cfr5/BR_3_Month_Two_Div.csv?dl=1',
        symbols.BRSpreadThreeMonthThreeDivision: 'https://www.dropbox.com/s/afrq21jpo30mdje/BR_3_Month_Three_Div.csv?dl=1',

        symbols.BRSpreadSixMonthZeroDivision: 'https://www.dropbox.com/s/9cpoc5fnlry1vtf/BR_6_Month_Zero_Div.csv?dl=1',
        symbols.BRSpreadSixMonthOneDivision: 'https://www.dropbox.com/s/1iyma1f2e3gqwo6/BR_6_Month_One_Div.csv?dl=1',
        symbols.BRSpreadSixMonthTwoDivision: 'https://www.dropbox.com/s/32l709iy4985onn/BR_6_Month_Two_Div.csv?dl=1',
        symbols.BRSpreadSixMonthThreeDivision: 'https://www.dropbox.com/s/qiyuzqoouodupwd/BR_6_Month_Three_Div.csv?dl=1',

        symbols.BRSpreadZeroDivision: 'https://www.dropbox.com/s/7sb1lxcto8loe4o/BR_0_Year_Offset_div.csv?dl=1',
        symbols.BRSpreadOneDivision: 'https://www.dropbox.com/s/5b2515oi8gt1nob/BR_1_Year_Offset_div.csv?dl=1'
    }

    class SpreadDataProvider(PythonData):

        def GetSource(self,
            config: SubscriptionDataConfig,
            date: datetime,
            isLive: bool) -> SubscriptionDataSource:
            return SubscriptionDataSource(links[symbol], SubscriptionTransportMedium.RemoteFile)

        def Reader(self,
            config: SubscriptionDataConfig,
            line: str,
            date: datetime,
            isLive: bool) -> BaseData:

            if not (line.strip()):
                return None

            index = SpreadDataProvider()
            index.Symbol = config.Symbol

            try:
                data = line.split(',')
                index.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S')
                index.EndTime = index.Time + timedelta(minutes=1)
                index.Value = data[4]
                index["open"] = float(data[1])
                index["high"] = float(data[2])
                index["low"] = float(data[3])
                index["close"] = float(data[4])
                index['volume'] = int(data[5])

            except ValueError:
                # Do nothing
                return None

            return index

    SpreadDataProvider.__qualname__ = f'{symbol}{SpreadDataProvider.__name__}'

    return SpreadDataProvider
#region imports
from AlgorithmImports import *
#endregion


class SpreadSymbols():

    def __init__(self):

        self.CLThreeMonthZero = 'CLThreeMonthZero'
        self.CLThreeMonthOne = 'CLThreeMonthOne'
        self.CLThreeMonthTwo = 'CLThreeMonthTwo'
        self.CLThreeMonthThree = 'CLThreeMonthThree'

        self.CLSixMonthZero = 'CLSixMonthZero'
        self.CLSixMonthOne = 'CLSixMonthOne'
        self.CLSixMonthTwo = 'CLSixMonthTwo'
        self.CLSixMonthThree = 'CLSixMonthThree'

        self.CLSpreadZero = 'CLSpreadZero'
        self.CLSpreadOne = 'CLSpreadOne'
        self.CLSpreadTwo = 'CLSpreadTwo'
        self.CLSpreadThree = 'CLSpreadThree'

        self.CLSpreadThreeMonthZeroDivision = 'CLSpreadThreeMonthZeroDivision'
        self.CLSpreadThreeMonthOneDivision = 'CLSpreadThreeMonthOneDivision'
        self.CLSpreadThreeMonthTwoDivision = 'CLSpreadThreeMonthTwoDivision'
        self.CLSpreadThreeMonthThreeDivision = 'CLSpreadThreeMonthThreeDivision'

        self.CLSpreadSixMonthZeroDivision = 'CLSpreadSixMonthZeroDivision'
        self.CLSpreadSixMonthOneDivision = 'CLSpreadSixMonthOneDivision'
        self.CLSpreadSixMonthTwoDivision = 'CLSpreadSixMonthTwoDivision'
        self.CLSpreadSixMonthThreeDivision = 'CLSpreadSixMonthThreeDivision'

        self.CLSpreadZeroDivision = 'CLSpreadZeroDivision'
        self.CLSpreadOneDivision = 'CLSpreadOneDivision'

        self.BRThreeMonthZero = 'BRThreeMonthZero'
        self.BRThreeMonthOne = 'BRThreeMonthOne'
        self.BRThreeMonthTwo = 'BRThreeMonthTwo'
        self.BRThreeMonthThree = 'BRThreeMonthThree'

        self.BRSixMonthZero = 'BRSixMonthZero'
        self.BRSixMonthOne = 'BRSixMonthOne'
        self.BRSixMonthTwo = 'BRSixMonthTwo'
        self.BRSixMonthThree = 'BRSixMonthThree'

        self.BRSpreadZero = 'BRSpreadZero'
        self.BRSpreadOne = 'BRSpreadOne'
        self.BRSpreadTwo = 'BRSpreadTwo'
        self.BRSpreadThree = 'BRSpreadThree'

        self.BRSpreadThreeMonthZeroDivision = 'BRSpreadThreeMonthZeroDivision'
        self.BRSpreadThreeMonthOneDivision = 'BRSpreadThreeMonthOneDivision'
        self.BRSpreadThreeMonthTwoDivision = 'BRSpreadThreeMonthTwoDivision'
        self.BRSpreadThreeMonthThreeDivision = 'BRSpreadThreeMonthThreeDivision'

        self.BRSpreadSixMonthZeroDivision = 'BRSpreadSixMonthZeroDivision'
        self.BRSpreadSixMonthOneDivision = 'BRSpreadSixMonthOneDivision'
        self.BRSpreadSixMonthTwoDivision = 'BRSpreadSixMonthTwoDivision'
        self.BRSpreadSixMonthThreeDivision = 'BRSpreadSixMonthThreeDivision'

        self.BRSpreadZeroDivision = 'BRSpreadZeroDivision'
        self.BRSpreadOneDivision = 'BRSpreadOneDivision'


class ArbSymbols():

    def __init__(self):
        self.ThreeMonthArbZero = 'ThreeMonthArbZero'
        self.ThreeMonthArbOne = 'ThreeMonthArbOne'
        self.ThreeMonthArbTwo = 'ThreeMonthArbTwo'
        self.ThreeMonthArbThree = 'ThreeMonthArbThree'

        self.SixMonthArbZero = 'SixMonthArbZero'
        self.SixMonthArbOne = 'SixMonthArbOne'
        self.SixMonthArbTwo = 'SixMonthArbTwo'
        self.SixMonthArbThree = 'SixMonthArbThree'
        
        self.ArbZero = 'ArbZero'
        self.ArbOne = 'ArbOne'
        self.ArbTwo = 'ArbTwo'
        self.ArbThree = 'ArbThree'

class OutrightSymbols():

    def __init__(self):
        self.CL = 'CL'
        self.BR = 'BR'

class DataSymbols():

    SPREADS = SpreadSymbols()
    ARBS = ArbSymbols()
    OUTRIGHTS = OutrightSymbols()

class DataInitialiser():

    def __init__(self, provider, feeModel = None):
        self.PROVIDER = provider
        self.FEE_MODEL = feeModel


def GetRollDates(symbol):

    roll_dates = {
        # CL
        SpreadSymbols().CLThreeMonthZero: [
            '2006-10-13',
            '2007-01-15',
            '2007-04-13',
            '2007-07-15',
            '2007-10-15',
            '2008-01-15',
            '2008-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2009-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2010-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2011-04-15',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2012-04-13',
            '2012-07-15',
            '2012-10-15',
            '2013-01-15',
            '2013-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2014-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2015-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2016-04-15',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2017-04-13',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2018-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2019-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2020-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2021-04-15',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-04-14',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
            '2023-03-29',
        ],

        SpreadSymbols().CLThreeMonthOne: [
            '2007-07-13',
            '2006-10-13',
            '2007-01-12',
            '2007-04-13',
            '2008-07-15',
            '2007-10-15',
            '2008-01-15',
            '2008-04-15',
            '2009-07-15',
            '2008-10-15',
            '2009-01-15',
            '2009-04-15',
            '2010-07-15',
            '2009-10-15',
            '2010-01-15',
            '2010-04-15',
            '2011-07-15',
            '2010-10-15',
            '2011-01-14',
            '2011-04-15',
            '2012-07-13',
            '2011-10-14',
            '2012-01-13',
            '2012-04-15',
            '2013-07-15',
            '2012-10-15',
            '2013-01-15',
            '2013-04-15',
            '2014-07-15',
            '2013-10-15',
            '2014-01-15',
            '2014-04-15',
            '2015-07-15',
            '2014-10-15',
            '2015-01-15',
            '2015-04-15',
            '2016-07-15',
            '2015-10-15',
            '2016-01-15',
            '2016-04-15',
            '2017-07-14',
            '2016-10-14',
            '2017-01-15',
            '2017-04-13',
            '2018-07-15',
            '2017-10-15',
            '2018-01-15',
            '2018-04-15',
            '2019-07-15',
            '2018-10-15',
            '2019-01-15',
            '2019-04-15',
            '2020-07-15',
            '2019-10-15',
            '2020-01-15',
            '2020-04-15',
            '2021-07-15',
            '2020-10-15',
            '2021-01-15',
            '2021-04-15',
            '2022-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-04-14',
            '2022-10-14',
            '2023-01-15',
            '2023-03-29',
        ],

        SpreadSymbols().CLThreeMonthTwo: [
            '2007-04-13',
            '2006-10-13',
            '2007-01-12',
            '2008-04-15',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2009-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2010-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2011-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2012-04-13',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2013-04-15',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2014-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2015-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2016-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2017-04-13',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2018-04-15',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2019-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2020-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2021-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2022-04-14',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2023-03-29',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
        ],

        SpreadSymbols().CLThreeMonthThree: [
            '2007-01-12',
            '2006-10-13',
            '2008-01-15',
            '2007-04-13',
            '2007-10-15',
            '2009-01-15',
            '2008-04-15',
            '2008-10-15',
            '2010-01-15',
            '2009-04-15',
            '2009-10-15',
            '2011-01-14',
            '2010-04-15',
            '2010-10-15',
            '2012-01-13',
            '2011-04-15',
            '2011-10-14',
            '2013-01-15',
            '2012-04-13',
            '2012-10-15',
            '2014-01-15',
            '2013-04-15',
            '2013-10-15',
            '2015-01-15',
            '2014-04-15',
            '2014-10-15',
            '2016-01-15',
            '2015-04-15',
            '2015-10-15',
            '2017-01-13',
            '2016-04-15',
            '2016-10-14',
            '2018-01-15',
            '2017-04-13',
            '2017-10-15',
            '2019-01-15',
            '2018-04-15',
            '2018-10-15',
            '2020-01-15',
            '2019-04-15',
            '2019-10-15',
            '2021-01-15',
            '2020-04-15',
            '2020-10-15',
            '2022-01-14',
            '2021-04-15',
            '2021-10-15',
            '2023-01-13',
            '2022-04-14',
            '2022-10-14',
            '2023-03-29',
        ],


        SpreadSymbols().CLSixMonthZero: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-15',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-30',
        ],

        SpreadSymbols().CLSixMonthOne: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-13',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-30',
        ],

        SpreadSymbols().CLSixMonthTwo: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-13',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-30',
        ],

        SpreadSymbols().CLSixMonthThree: [
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-13',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-13',
            '2018-04-13',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-30',
        ],


        SpreadSymbols().CLSpreadZero: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-19',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().CLSpreadOne: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-19',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().CLSpreadTwo: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().CLSpreadThree: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        # BRENT
        SpreadSymbols().BRThreeMonthZero: [
            '2006-10-13',
            '2007-01-15',
            '2007-04-13',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2008-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2009-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2010-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2011-04-15',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2012-04-15',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2013-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2014-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2015-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2016-04-15',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2017-04-13',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2018-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2019-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2020-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2021-04-15',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-04-14',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
            '2023-03-30',
        ],

        SpreadSymbols().BRThreeMonthOne: [
            '2007-07-13',
            '2006-10-13',
            '2007-01-15',
            '2007-04-13',
            '2008-07-15',
            '2007-10-15',
            '2008-01-15',
            '2008-04-15',
            '2009-07-15',
            '2008-10-15',
            '2009-01-15',
            '2009-04-15',
            '2010-07-15',
            '2009-10-15',
            '2010-01-15',
            '2010-04-15',
            '2011-07-15',
            '2010-10-15',
            '2011-01-14',
            '2011-04-15',
            '2012-07-13',
            '2011-10-14',
            '2012-01-13',
            '2012-04-13',
            '2013-07-15',
            '2012-10-15',
            '2013-01-15',
            '2013-04-15',
            '2014-07-15',
            '2013-10-15',
            '2014-01-15',
            '2014-04-15',
            '2015-07-15',
            '2014-10-15',
            '2015-01-15',
            '2015-04-15',
            '2016-07-15',
            '2015-10-15',
            '2016-01-15',
            '2016-04-15',
            '2017-07-14',
            '2016-10-14',
            '2017-01-15',
            '2017-04-13',
            '2018-07-13',
            '2017-10-15',
            '2018-01-15',
            '2018-04-15',
            '2019-07-15',
            '2018-10-15',
            '2019-01-15',
            '2019-04-15',
            '2020-07-15',
            '2019-10-15',
            '2020-01-15',
            '2020-04-15',
            '2021-07-15',
            '2020-10-15',
            '2021-01-15',
            '2021-04-15',
            '2022-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-04-14',
            '2022-10-14',
            '2023-01-15',
            '2023-03-30',
        ],

        SpreadSymbols().BRThreeMonthTwo: [
            '2007-04-13',
            '2006-10-13',
            '2007-01-15',
            '2008-04-15',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2009-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2010-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2011-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2012-04-13',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2013-04-15',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2014-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2015-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2016-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2017-04-13',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2018-04-15',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2019-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2020-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2021-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2022-04-14',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2023-03-30',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
        ],

        SpreadSymbols().BRThreeMonthThree: [
            '2007-01-15',
            '2006-10-13',
            '2008-01-15',
            '2007-04-13',
            '2007-10-15',
            '2009-01-15',
            '2008-04-15',
            '2008-10-15',
            '2010-01-15',
            '2009-04-15',
            '2009-10-15',
            '2011-01-14',
            '2010-04-15',
            '2010-10-15',
            '2012-01-13',
            '2011-04-15',
            '2011-10-14',
            '2013-01-15',
            '2012-04-13',
            '2012-10-15',
            '2014-01-15',
            '2013-04-15',
            '2013-10-15',
            '2015-01-15',
            '2014-04-15',
            '2014-10-15',
            '2016-01-15',
            '2015-04-15',
            '2015-10-15',
            '2017-01-13',
            '2016-04-15',
            '2016-10-14',
            '2018-01-15',
            '2017-04-13',
            '2017-10-15',
            '2019-01-15',
            '2018-04-15',
            '2018-10-15',
            '2020-01-15',
            '2019-04-15',
            '2019-10-15',
            '2021-01-15',
            '2020-04-15',
            '2020-10-15',
            '2022-01-14',
            '2021-04-15',
            '2021-10-15',
            '2023-01-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-30',
        ],

        SpreadSymbols().BRSixMonthZero: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-13',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-29',
        ],

        SpreadSymbols().BRSixMonthOne: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-15',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-31',
        ],

        SpreadSymbols().BRSixMonthTwo: [
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-15',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-31',
        ],

        SpreadSymbols().BRSixMonthThree: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-15',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-29',
        ],

        SpreadSymbols().BRSpreadZero: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-19',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().BRSpreadOne: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().BRSpreadTwo: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        SpreadSymbols().BRSpreadThree: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        # Arbs
        ArbSymbols().ThreeMonthArbZero: [
            '2006-10-13',
            '2007-01-15',
            '2007-04-13',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2008-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2009-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2010-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2011-04-15',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2012-04-13',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2013-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2014-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2015-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2016-04-15',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2017-04-13',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2018-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2019-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2020-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2021-04-15',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-04-14',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
            '2023-03-29',
        ],

        ArbSymbols().ThreeMonthArbOne: [
            '2007-04-13',
            '2006-10-13',
            '2007-01-12',
            '2008-04-15',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2009-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2010-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2011-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2012-04-13',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2013-04-15',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2014-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2015-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2016-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2017-04-13',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2018-04-15',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2019-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2020-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2021-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2022-04-14',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
        ],

        ArbSymbols().ThreeMonthArbTwo: [
            '2007-04-13',
            '2006-10-13',
            '2007-01-12',
            '2008-04-15',
            '2007-07-13',
            '2007-10-15',
            '2008-01-15',
            '2009-04-15',
            '2008-07-15',
            '2008-10-15',
            '2009-01-15',
            '2010-04-15',
            '2009-07-15',
            '2009-10-15',
            '2010-01-15',
            '2011-04-15',
            '2010-07-15',
            '2010-10-15',
            '2011-01-14',
            '2012-04-13',
            '2011-07-15',
            '2011-10-14',
            '2012-01-13',
            '2013-04-15',
            '2012-07-13',
            '2012-10-15',
            '2013-01-15',
            '2014-04-15',
            '2013-07-15',
            '2013-10-15',
            '2014-01-15',
            '2015-04-15',
            '2014-07-15',
            '2014-10-15',
            '2015-01-15',
            '2016-04-15',
            '2015-07-15',
            '2015-10-15',
            '2016-01-15',
            '2017-04-13',
            '2016-07-15',
            '2016-10-14',
            '2017-01-15',
            '2018-04-15',
            '2017-07-14',
            '2017-10-15',
            '2018-01-15',
            '2019-04-15',
            '2018-07-15',
            '2018-10-15',
            '2019-01-15',
            '2020-04-15',
            '2019-07-15',
            '2019-10-15',
            '2020-01-15',
            '2021-04-15',
            '2020-07-15',
            '2020-10-15',
            '2021-01-15',
            '2022-04-14',
            '2021-07-15',
            '2021-10-15',
            '2022-01-14',
            '2022-07-15',
            '2022-10-14',
            '2023-01-15',
        ],

        ArbSymbols().ThreeMonthArbThree: [
            '2007-01-12',
            '2006-10-13',
            '2008-01-15',
            '2007-04-13',
            '2007-10-15',
            '2009-01-15',
            '2008-04-15',
            '2008-10-15',
            '2010-01-15',
            '2009-04-15',
            '2009-10-15',
            '2011-01-14',
            '2010-04-15',
            '2010-10-15',
            '2012-01-13',
            '2011-04-15',
            '2011-10-14',
            '2013-01-15',
            '2012-04-13',
            '2012-10-15',
            '2014-01-15',
            '2013-04-15',
            '2013-10-15',
            '2015-01-15',
            '2014-04-15',
            '2014-10-15',
            '2016-01-15',
            '2015-04-15',
            '2015-10-15',
            '2017-01-13',
            '2016-04-15',
            '2016-10-14',
            '2018-01-15',
            '2017-04-13',
            '2017-10-15',
            '2019-01-15',
            '2018-04-15',
            '2018-10-15',
            '2020-01-15',
            '2019-04-15',
            '2019-10-15',
            '2021-01-15',
            '2020-04-15',
            '2020-10-15',
            '2022-01-14',
            '2021-04-15',
            '2021-10-15',
            '2023-01-13',
            '2022-04-14',
            '2022-10-14',
            '2023-03-29',
        ],

        ArbSymbols().SixMonthArbZero: [
            '2006-10-13',
            '2007-04-13',
            '2007-10-15',
            '2008-04-15',
            '2008-10-15',
            '2009-04-15',
            '2009-10-15',
            '2010-04-15',
            '2010-10-15',
            '2011-04-15',
            '2011-10-14',
            '2012-04-13',
            '2012-10-15',
            '2013-04-15',
            '2013-10-15',
            '2014-04-15',
            '2014-10-15',
            '2015-04-15',
            '2015-10-15',
            '2016-04-15',
            '2016-10-14',
            '2017-04-13',
            '2017-10-15',
            '2018-04-15',
            '2018-10-15',
            '2019-04-15',
            '2019-10-15',
            '2020-04-15',
            '2020-10-15',
            '2021-04-15',
            '2021-10-15',
            '2022-04-14',
            '2022-10-14',
            '2023-03-29',
        ],

        ArbSymbols().SixMonthArbOne: [
            '2007-04-13',
            '2006-10-13',
            '2008-04-15',
            '2007-10-15',
            '2009-04-15',
            '2008-10-15',
            '2010-04-15',
            '2009-10-15',
            '2011-04-15',
            '2010-10-15',
            '2012-04-13',
            '2011-10-14',
            '2013-04-15',
            '2012-10-15',
            '2014-04-15',
            '2013-10-15',
            '2015-04-15',
            '2014-10-15',
            '2016-04-15',
            '2015-10-15',
            '2017-04-13',
            '2016-10-14',
            '2018-04-15',
            '2017-10-15',
            '2019-04-15',
            '2018-10-15',
            '2020-04-15',
            '2019-10-15',
            '2021-04-15',
            '2020-10-15',
            '2022-04-14',
            '2021-10-15',
            '2023-03-30',
            '2022-10-14',
        ],

        ArbSymbols().SixMonthArbTwo: [
            '2007-10-15',
            '2007-04-13',
            '2008-10-15',
            '2008-04-15',
            '2009-10-15',
            '2009-04-15',
            '2010-10-15',
            '2010-04-15',
            '2011-10-14',
            '2011-04-15',
            '2012-10-15',
            '2012-04-13',
            '2013-10-15',
            '2013-04-15',
            '2014-10-15',
            '2014-04-15',
            '2015-10-15',
            '2015-04-15',
            '2016-10-14',
            '2016-04-15',
            '2017-10-15',
            '2017-04-13',
            '2018-10-15',
            '2018-04-15',
            '2019-10-15',
            '2019-04-15',
            '2020-10-15',
            '2020-04-15',
            '2021-10-15',
            '2021-04-15',
            '2022-10-14',
            '2022-04-14',
            '2023-03-30',
        ],

        ArbSymbols().SixMonthArbThree: [
            '2007-04-13',
            '2008-04-15',
            '2007-10-15',
            '2009-04-15',
            '2008-10-15',
            '2010-04-15',
            '2009-10-15',
            '2011-04-15',
            '2010-10-15',
            '2012-04-13',
            '2011-10-14',
            '2013-04-15',
            '2012-10-15',
            '2014-04-15',
            '2013-10-15',
            '2015-04-15',
            '2014-10-15',
            '2016-04-15',
            '2015-10-15',
            '2017-04-13',
            '2016-10-14',
            '2018-04-13',
            '2017-10-13',
            '2019-04-15',
            '2018-10-15',
            '2020-04-15',
            '2019-10-15',
            '2021-04-15',
            '2020-10-15',
            '2022-04-14',
            '2021-10-15',
            '2023-03-29',
            '2022-10-14',
        ],

        ArbSymbols().ArbZero: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-19',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        ArbSymbols().ArbOne: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        ArbSymbols().ArbTwo: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        ArbSymbols().ArbThree: [
            '2006-10-19',
            '2007-10-19',
            '2008-10-17',
            '2009-10-19',
            '2010-10-19',
            '2011-10-19',
            '2012-10-19',
            '2013-10-18',
            '2014-10-17',
            '2015-10-19',
            '2016-10-19',
            '2017-10-19',
            '2018-10-19',
            '2019-10-18',
            '2020-10-19',
            '2021-10-19',
            '2022-10-19',
            '2023-03-09',
        ],

        OutrightSymbols().CL: [
            '2000-01-14',
            '2000-02-18',
            '2000-03-21',
            '2000-04-19',
            '2000-05-22',
            '2000-06-20',
            '2000-07-20',
            '2000-08-22',
            '2000-09-01',
            '2000-10-20',
            '2000-11-17',
            '2000-12-19',
            '2001-01-12',
            '2001-02-16',
            '2001-03-20',
            '2001-04-20',
            '2001-05-22',
            '2001-06-20',
            '2001-07-20',
            '2001-08-21',
            '2001-09-11',
            '2001-10-22',
            '2001-11-19',
            '2001-12-18',
            '2002-01-18',
            '2002-02-15',
            '2002-03-20',
            '2002-04-22',
            '2002-05-21',
            '2002-06-20',
            '2002-07-03',
            '2002-08-20',
            '2002-09-20',
            '2002-10-22',
            '2002-11-20',
            '2002-12-19',
            '2003-01-17',
            '2003-02-14',
            '2003-03-20',
            '2003-04-22',
            '2003-05-20',
            '2003-06-20',
            '2003-07-03',
            '2003-08-20',
            '2003-09-22',
            '2003-10-21',
            '2003-11-20',
            '2003-12-19',
            '2004-01-16',
            '2004-02-13',
            '2004-03-22',
            '2004-04-20',
            '2004-05-20',
            '2004-06-22',
            '2004-07-20',
            '2004-08-20',
            '2004-09-21',
            '2004-10-20',
            '2004-11-19',
            '2004-12-20',
            '2005-01-14',
            '2005-02-18',
            '2005-03-21',
            '2005-04-20',
            '2005-05-20',
            '2005-06-21',
            '2005-07-20',
            '2005-08-22',
            '2005-09-20',
            '2005-10-20',
            '2005-11-18',
            '2005-12-20',
            '2005-12-20',
            '2006-02-17',
            '2006-03-21',
            '2006-04-20',
            '2006-05-22',
            '2006-06-20',
            '2006-07-20',
            '2006-08-22',
            '2006-09-20',
            '2006-10-20',
            '2006-11-17',
            '2006-12-19',
            '2007-01-22',
            '2007-02-20',
            '2007-03-20',
            '2007-04-20',
            '2007-05-22',
            '2007-06-20',
            '2007-07-20',
            '2007-08-21',
            '2007-09-20',
            '2007-10-22',
            '2007-11-16',
            '2007-12-18',
            '2008-01-22',
            '2008-02-20',
            '2008-03-19',
            '2008-04-22',
            '2008-05-20',
            '2008-06-20',
            '2008-07-22',
            '2008-08-20',
            '2008-09-22',
            '2008-10-21',
            '2008-11-20',
            '2008-12-19',
            '2009-01-20',
            '2009-02-20',
            '2009-03-20',
            '2009-04-21',
            '2009-05-19',
            '2009-06-22',
            '2009-07-21',
            '2009-08-20',
            '2009-09-22',
            '2009-10-20',
            '2009-11-20',
            '2009-12-21',
            '2010-01-20',
            '2010-02-22',
            '2010-03-22',
            '2010-04-20',
            '2010-05-20',
            '2010-06-22',
            '2010-07-20',
            '2010-08-20',
            '2010-09-21',
            '2010-10-20',
            '2010-11-19',
            '2010-12-20',
            '2011-01-20',
            '2011-02-22',
            '2011-03-22',
            '2011-04-19',
            '2011-05-20',
            '2011-06-21',
            '2011-07-20',
            '2011-08-22',
            '2011-09-20',
            '2011-10-20',
            '2011-11-18',
            '2011-12-20',
            '2012-01-20',
            '2012-02-21',
            '2012-03-20',
            '2012-04-20',
            '2012-05-22',
            '2012-06-20',
            '2012-07-20',
            '2012-08-21',
            '2012-09-20',
            '2012-10-22',
            '2012-11-16',
            '2012-12-19',
            '2013-01-22',
            '2013-02-20',
            '2013-03-20',
            '2013-04-22',
            '2013-05-21',
            '2013-06-20',
            '2013-07-22',
            '2013-08-20',
            '2013-09-20',
            '2013-10-22',
            '2013-11-20',
            '2013-12-19',
            '2014-01-21',
            '2014-02-20',
            '2014-03-20',
            '2014-04-22',
            '2014-05-20',
            '2014-06-20',
            '2014-07-22',
            '2014-08-20',
            '2014-09-22',
            '2014-10-21',
            '2014-11-20',
            '2014-12-19',
            '2015-01-20',
            '2015-02-20',
            '2015-03-20',
            '2015-04-21',
            '2015-05-19',
            '2015-06-22',
            '2015-07-21',
            '2015-08-20',
            '2015-09-22',
            '2015-10-20',
            '2015-11-20',
            '2015-12-21',
            '2016-01-20',
            '2016-02-22',
            '2016-03-21',
            '2016-04-20',
            '2016-05-20',
            '2016-06-21',
            '2016-07-20',
            '2016-08-22',
            '2016-09-20',
            '2016-10-20',
            '2016-11-21',
            '2016-12-20',
            '2017-01-20',
            '2017-02-21',
            '2017-03-21',
            '2017-04-20',
            '2017-05-22',
            '2017-06-20',
            '2017-07-20',
            '2017-08-22',
            '2017-09-20',
            '2017-10-20',
            '2017-11-20',
            '2017-12-19',
            '2018-01-22',
            '2018-02-20',
            '2018-03-20',
            '2018-04-20',
            '2018-05-22',
            '2018-06-20',
            '2018-07-20',
            '2018-08-21',
            '2018-09-20',
            '2018-10-22',
            '2018-11-19',
            '2018-12-19',
            '2019-01-22',
            '2019-02-20',
            '2019-03-20',
            '2019-04-22',
            '2019-05-21',
            '2019-06-20',
            '2019-07-22',
            '2019-08-20',
            '2019-09-20',
            '2019-10-22',
            '2019-11-20',
            '2019-12-19',
            '2020-01-21',
            '2020-02-20',
            '2020-03-20',
            '2020-04-21',
            '2020-05-19',
            '2020-06-22',
            '2020-07-21',
            '2020-08-20',
            '2020-09-22',
            '2020-10-20',
            '2020-11-20',
            '2020-12-21',
            '2021-01-20',
            '2021-02-22',
            '2021-03-22',
            '2021-04-20',
            '2021-05-20',
            '2021-06-22',
            '2021-07-20',
            '2021-08-20',
            '2021-09-21',
            '2021-10-20',
            '2021-11-19',
            '2021-12-20',
            '2022-01-20',
            '2022-02-22',
            '2022-03-22',
            '2022-04-20',
            '2022-05-20',
            '2022-06-21',
            '2022-07-20',
            '2022-08-22',
            '2022-09-20',
            '2022-10-20',
            '2022-11-21',
            '2022-12-20',
            '2023-01-20',
            '2023-02-21',
        ],

        OutrightSymbols().BR: [
            '2003-11-07',
            '2003-12-09',
            '2003-12-24',
            '2004-02-10',
            '2004-03-09',
            '2004-04-08',
            '2004-04-30',
            '2004-05-28',
            '2004-07-09',
            '2004-08-09',
            '2004-08-27',
            '2004-10-12',
            '2004-11-09',
            '2004-12-09',
            '2004-12-24',
            '2005-02-09',
            '2005-03-09',
            '2005-03-24',
            '2005-04-29',
            '2005-05-27',
            '2005-07-11',
            '2005-08-10',
            '2005-08-26',
            '2005-10-07',
            '2005-11-09',
            '2005-12-12',
            '2005-12-23',
            '2006-02-09',
            '2006-03-09',
            '2006-04-09',
            '2006-04-13',
            '2006-05-26',
            '2006-07-07',
            '2006-08-09',
            '2006-09-12',
            '2006-10-11',
            '2006-11-10',
            '2006-12-08',
            '2006-12-22',
            '2007-02-09',
            '2007-03-12',
            '2007-04-05',
            '2007-05-10',
            '2007-06-10',
            '2007-07-09',
            '2007-08-13',
            '2007-09-10',
            '2007-10-10',
            '2007-11-13',
            '2007-12-11',
            '2007-12-24',
            '2008-02-12',
            '2008-03-11',
            '2008-04-11',
            '2008-05-12',
            '2008-06-11',
            '2008-07-13',
            '2008-08-11',
            '2008-09-11',
            '2008-10-12',
            '2008-11-11',
            '2008-12-12',
            '2008-12-24',
            '2009-02-09',
            '2009-03-11',
            '2009-04-09',
            '2009-05-12',
            '2009-06-11',
            '2009-07-12',
            '2009-08-11',
            '2009-09-13',
            '2009-10-12',
            '2009-11-10',
            '2009-12-14',
            '2010-01-12',
            '2010-02-09',
            '2010-03-11',
            '2010-04-12',
            '2010-05-11',
            '2010-06-13',
            '2010-07-12',
            '2010-08-12',
            '2010-09-12',
            '2010-10-11',
            '2010-11-11',
            '2010-12-13',
            '2011-01-11',
            '2011-02-09',
            '2011-03-13',
            '2011-04-11',
            '2011-05-12',
            '2011-06-13',
            '2011-07-12',
            '2011-08-14',
            '2011-09-12',
            '2011-10-11',
            '2011-11-13',
            '2011-12-13',
            '2011-12-23',
            '2012-02-12',
            '2012-03-13',
            '2012-04-11',
            '2012-05-14',
            '2012-06-12',
            '2012-07-12',
            '2012-08-13',
            '2012-09-11',
            '2012-10-11',
            '2012-11-13',
            '2012-12-11',
            '2012-12-24',
            '2013-02-11',
            '2013-03-11',
            '2013-04-10',
            '2013-05-13',
            '2013-06-10',
            '2013-07-11',
            '2013-08-12',
            '2013-09-10',
            '2013-10-13',
            '2013-11-11',
            '2013-12-11',
            '2013-12-24',
            '2014-02-10',
            '2014-03-11',
            '2014-04-10',
            '2014-05-12',
            '2014-06-10',
            '2014-07-10',
            '2014-08-11',
            '2014-09-10',
            '2014-10-09',
            '2014-11-10',
            '2014-12-11',
            '2014-12-24',
            '2015-02-09',
            '2015-03-11',
            '2015-04-09',
            '2015-05-11',
            '2015-06-10',
            '2015-07-12',
            '2015-08-11',
            '2015-09-10',
            '2015-10-11',
            '2015-11-10',
            '2015-12-10',
            '2016-01-11',
            '2016-01-29',
            '2016-02-29',
            '2016-03-31',
            '2016-04-29',
            '2016-05-31',
            '2016-06-30',
            '2016-07-29',
            '2016-08-31',
            '2016-09-30',
            '2016-10-31',
            '2016-11-30',
            '2016-12-23',
            '2017-01-31',
            '2017-02-28',
            '2017-03-31',
            '2017-04-28',
            '2017-05-31',
            '2017-06-30',
            '2017-07-31',
            '2017-08-31',
            '2017-09-29',
            '2017-10-31',
            '2017-11-30',
            '2017-12-22',
            '2018-01-31',
            '2018-02-28',
            '2018-03-29',
            '2018-04-30',
            '2018-05-31',
            '2018-06-29',
            '2018-07-31',
            '2018-08-31',
            '2018-09-28',
            '2018-10-31',
            '2018-11-30',
            '2018-12-24',
            '2019-01-31',
            '2019-02-28',
            '2019-03-29',
            '2019-04-30',
            '2019-05-31',
            '2019-06-28',
            '2019-07-31',
            '2019-08-30',
            '2019-09-30',
            '2019-10-31',
            '2019-11-29',
            '2019-12-24',
            '2020-01-31',
            '2020-02-28',
            '2020-03-31',
            '2020-04-30',
            '2020-05-29',
            '2020-06-30',
            '2020-07-31',
            '2020-08-28',
            '2020-09-30',
            '2020-10-30',
            '2020-11-30',
            '2020-12-30',
            '2021-01-29',
            '2021-02-26',
            '2021-03-31',
            '2021-04-30',
            '2021-05-28',
            '2021-06-30',
            '2021-07-30',
            '2021-08-31',
            '2021-09-30',
            '2021-10-29',
            '2021-11-30',
            '2021-12-30',
            '2022-01-31',
            '2022-02-28',
            '2022-03-31',
            '2022-04-29',
            '2022-05-31',
            '2022-06-30',
            '2022-07-29',
            '2022-08-31',
            '2022-09-30',
            '2022-10-31',
            '2022-11-30',
            '2022-12-23',
            '2023-01-31',
            '2023-02-28',
        ]
    }

    return roll_dates[symbol]
 # region imports
from AlgorithmImports import *
from data.ManageData import ManageData
from data.data_utils import DataSymbols
from strategies.CalenderSpreadStrategy import CalendarSpreadStrategy
from strategies.ArbSpreadStrategy import ArbSpreadStrategy
from strategies.DivisionSpreadStrategy import CalendarDivisionSpreadStrategy
from strategies.DailyMovingAverageStrategy import DailyMovingAverageStrategy
from strategies.strategy_utils import *
# endregion

Symbols = DataSymbols()

class AlertFluorescentPinkFlamingo(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2012, 1, 1)  # Set Start Date
        self.SetEndDate(2022,12,31)
        self.SetCash(200000)  # Set Strategy Cash

        self.SetTimeZone(TimeZones.Utc)

        """
        To optimise use:
            For whole numbers use   int(self.GetParameter(<PARAMETER_NAME>))
            For decimals use        float(self.GetParameter(<PARAMETER_NAME>))
        """

        init_strategies = {
            # '3 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRThreeMonthOne, 
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', -120)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -5)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -200)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 5)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 100)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 25)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 400)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 25))
            #         )),
            # '6 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSixMonthZero, 
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # '12 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadOne, 
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 100)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -25)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -250)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 25)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 350)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 25)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 750)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 25)),
            #         strategy_weight = 1
            #         )),
            # '12 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 150, 
            #         long_entry_step = -25, 
            #         long_stop_loss = -300, 
            #         long_profit_target = 25, 
            #         initial_short_entry = 350, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 750, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            # '12 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -250, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -450, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 350, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            # '12 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -250, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -450, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 350, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            # '12 Month BR Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -250, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -450, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 350, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            # '3 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLThreeMonthThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 50)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -25)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -50)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 25)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 150)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 25)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 400)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 25)),
            #         strategy_weight = 1
            #         )),
            #  '3 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLThreeMonthZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -250, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -450, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 350, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            #  '3 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLThreeMonthOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -100, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -300, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 250, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            #  '3 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLThreeMonthTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -75, 
            #         long_entry_step = -15, 
            #         long_stop_loss = -250, 
            #         long_profit_target = 15, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 200, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            #  '3 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLThreeMonthThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 50, 
            #         long_entry_step = -25, 
            #         long_stop_loss = -50, 
            #         long_profit_target = 25, 
            #         initial_short_entry = 150, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 400, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
            # '6 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSixMonthThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 25)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -50)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -250)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 50)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 50)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 30)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 275)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 30)),
            #         strategy_weight = 1
            #         )),
            #  '6 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSixMonthZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -150, 
            #         long_entry_step = -30, 
            #         long_stop_loss = -650, 
            #         long_profit_target = 30, 
            #         initial_short_entry = 200, 
            #         short_entry_step = 25, 
            #         short_stop_loss = 550, 
            #         short_profit_target = 25,
            #         strategy_weight = 1
            #         )),
             '6 Month CL Calendar Spread' : StrategyInitialiser(
                strategy = CalendarSpreadStrategy, 
                symbol = Symbols.SPREADS.CLSixMonthOne,
                strategy_parameters = StrategyParameters(
                    initial_long_entry = -150, 
                    long_entry_step = -50, 
                    long_stop_loss = -400, 
                    long_profit_target = 50, 
                    initial_short_entry = 150, 
                    short_entry_step = 25, 
                    short_stop_loss = 400, 
                    short_profit_target = 25,
                    strategy_weight = 0.5
                    )),
            #  '6 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSixMonthTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 100, 
            #         long_entry_step = -50, 
            #         long_stop_loss = -250, 
            #         long_profit_target = 50, 
            #         initial_short_entry = 150, 
            #         short_entry_step = 30, 
            #         short_stop_loss = 650, 
            #         short_profit_target = 30,
            #         strategy_weight = 1
            #         )),
            #  '6 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSixMonthThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 25, 
            #         long_entry_step = -50, 
            #         long_stop_loss = -250, 
            #         long_profit_target = 50, 
            #         initial_short_entry = 50, 
            #         short_entry_step = 30, 
            #         short_stop_loss = 275, 
            #         short_profit_target = 30,
            #         strategy_weight = 1
            #         )),
            # '12 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 100)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -30)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -425)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 30)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 25)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 300)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 25)),
            #         strategy_weight = 1
            #         )),
            #  '12 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 400, 
            #         long_entry_step = -10, 
            #         long_stop_loss = 0, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 100, 
            #         short_entry_step = 20, 
            #         short_stop_loss = 500, 
            #         short_profit_target = 20,
            #         strategy_weight = 1
            #         )),
            # '12 Month CL Calendar Spread' : StrategyInitialiser(
            #     strategy = CalendarSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = -100, 
            #         long_entry_step = -10, 
            #         long_stop_loss = -700, 
            #         long_profit_target = 10, 
            #         initial_short_entry = 100, 
            #         short_entry_step = 15, 
            #         short_stop_loss = 500, 
            #         short_profit_target = 15,
            #         strategy_weight = 1
            #         )),
            '12 Month CL Calendar Spread' : StrategyInitialiser(
                strategy = CalendarSpreadStrategy, 
                symbol = Symbols.SPREADS.CLSpreadTwo,
                strategy_parameters = StrategyParameters(
                    initial_long_entry = 100, 
                    long_entry_step = -25, 
                    long_stop_loss = -425, 
                    long_profit_target = 25, 
                    initial_short_entry = 0, 
                    short_entry_step = 25, 
                    short_stop_loss = 300, 
                    short_profit_target = 25,
                    strategy_weight = 0.5
                    )),
            # 'Arb Strategy 3 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ThreeMonthArbThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -5)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -150)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 5)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', -25)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 5)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 150)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 5)),
            #         strategy_weight = 0.5
            #         )),         
            #  'Arb Strategy 3 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ThreeMonthArbThree,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 0, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -150, 
            #         long_profit_target = 5, 
            #         initial_short_entry = -25, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 150, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),    
            #  'Arb Strategy 3 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ThreeMonthArbTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 0, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -200, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 200, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),    
            #  'Arb Strategy 3 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ThreeMonthArbOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 0, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -175, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 175, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),        
            #  'Arb Strategy 3 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ThreeMonthArbZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 25, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -100, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 175, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),
            # 'Arb Strategy 6 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.SixMonthArbTwo,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 25)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -5)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -100)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 5)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', -25)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 5)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 150)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 5)),
            #         strategy_weight = 0.5
            #         )),
             'Arb Strategy 6 Month' : StrategyInitialiser(
                strategy = ArbSpreadStrategy, 
                symbol = Symbols.ARBS.SixMonthArbTwo,
                strategy_parameters = StrategyParameters(
                    initial_long_entry = 25, 
                    long_entry_step = -5, 
                    long_stop_loss = -100, 
                    long_profit_target = 5, 
                    initial_short_entry = -25, 
                    short_entry_step = 5, 
                    short_stop_loss = 150, 
                    short_profit_target = 5,
                    strategy_weight = 0.25
                    )),
            # 'Arb Strategy 6 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.SixMonthArbOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 25, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -100, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 125, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),
            # 'Arb Strategy 6 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.SixMonthArbZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 0, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -125, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 120, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),
            # 'Arb Strategy 12 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ArbZero,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', -5)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', -150)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 5)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 5)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 200)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 5)),
            #         strategy_weight = 0.5
            #         )),
            # 'Arb Strategy 12 Month' : StrategyInitialiser(
            #     strategy = ArbSpreadStrategy, 
            #     symbol = Symbols.ARBS.ArbOne,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = 0, 
            #         long_entry_step = -5, 
            #         long_stop_loss = -125, 
            #         long_profit_target = 5, 
            #         initial_short_entry = 0, 
            #         short_entry_step = 5, 
            #         short_stop_loss = 200, 
            #         short_profit_target = 5,
            #         strategy_weight = 0.5
            #         )),
            'Arb Strategy 12 Month' : StrategyInitialiser(
                strategy = ArbSpreadStrategy, 
                symbol = Symbols.ARBS.ArbZero,
                strategy_parameters = StrategyParameters(
                    initial_long_entry = 0, 
                    long_entry_step = -5, 
                    long_stop_loss = -150, 
                    long_profit_target = 5, 
                    initial_short_entry = 0, 
                    short_entry_step = 5, 
                    short_stop_loss = 200, 
                    short_profit_target = 5,
                    strategy_weight = 0.25
                    )),
            # 'Div Strategy BR 3 Month' : StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadThreeMonthZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'Div Strategy CL 3 Month' : StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadThreeMonthZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'Div Strategy BR 6 Month': StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadSixMonthZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'Div Strategy CL 6 Month': StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadSixMonthZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'Div Strategy BR 12 Month': StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.BRSpreadZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'Div Strategy CL 12 Month': StrategyInitialiser(
            #     strategy = CalendarDivisionSpreadStrategy, 
            #     symbol = Symbols.SPREADS.CLSpreadZeroDivision,
            #     strategy_parameters = StrategyParameters(
            #         initial_long_entry = int(self.GetParameter('initial_long_entry', 0)), 
            #         long_entry_step = int(self.GetParameter('long_entry_step', 0)), 
            #         long_stop_loss = int(self.GetParameter('long_stop_loss', 0)), 
            #         long_profit_target = int(self.GetParameter('long_profit_target', 0)), 
            #         initial_short_entry = int(self.GetParameter('initial_short_entry', 0)), 
            #         short_entry_step = int(self.GetParameter('short_entry_step', 0)), 
            #         short_stop_loss = int(self.GetParameter('short_stop_loss', 0)), 
            #         short_profit_target = int(self.GetParameter('short_profit_target', 0)),
            #         )),
            # 'BR DMA Strategy': StrategyInitialiser(
            #     strategy = DailyMovingAverageStrategy, 
            #     symbol = Symbols.OUTRIGHTS.BR, 
            #     strategy_parameters = DmaStrategyParameters(
            #         long_fast = int(self.GetParameter('long_fast', 10)), 
            #         long_slow = int(self.GetParameter('long_slow', 30)), 
            #         short_fast = int(self.GetParameter('short_fast', 1)), 
            #         short_slow = int(self.GetParameter('short_slow', 3)), 
            #         tolerance = float(self.GetParameter('tolerance', 0.00015)),
            #         )),
            # 'CL DMA Strategy': StrategyInitialiser(
            #     strategy = DailyMovingAverageStrategy, 
            #     symbol = Symbols.OUTRIGHTS.CL, 
            #     strategy_parameters = DmaStrategyParameters(
            #         long_fast = int(self.GetParameter('long_fast', 10)), 
            #         long_slow = int(self.GetParameter('long_slow', 30)), 
            #         short_fast = int(self.GetParameter('short_fast', 1)), 
            #         short_slow = int(self.GetParameter('short_slow', 3)), 
            #         tolerance = float(self.GetParameter('tolerance', 0.00015)),
            #         )),
        }

        # Extract the symbols that data needs to be fetched
        spreads_data_fetch = { 
            strategy.SYMBOL: True for strategy in init_strategies.values() 
                if strategy.SYMBOL in vars(Symbols.SPREADS).values()
        }

        spreads_signal_data_fetch = {
            strategy.STRATEGY_OPTIONS.get('signal_contract', ''): True for strategy in init_strategies.values() 
                if strategy.STRATEGY_OPTIONS.get('signal_contract', '') in vars(Symbols.SPREADS).values() 
        }

        spreads_data_fetch = {
            **spreads_data_fetch,
            **spreads_signal_data_fetch
        }

        arbs_data_fetch = { 
            strategy.SYMBOL: True for strategy in init_strategies.values() 
            if strategy.SYMBOL in vars(Symbols.ARBS).values() 
        }

        or_data_fetch = { 
            strategy.SYMBOL: True for strategy in init_strategies.values() 
            if strategy.SYMBOL in vars(Symbols.OUTRIGHTS).values() 
        }

        manageData = ManageData(
            self, 
            spreads = spreads_data_fetch, 
            arbs = arbs_data_fetch, 
            outrights = or_data_fetch
        )

        # Initialises strategies to trade
        self.Strategies = {
            key: value.STRATEGY(
                self, 
                value.SYMBOL,
                manageData.data[value.SYMBOL], 
                strategy_parameters = value.STRATEGY_PARAMETERS,
                signal_contract = manageData.data[value.STRATEGY_OPTIONS.get('signal_contract')] if 'signal_contract' in value.STRATEGY_OPTIONS else None,
                ) for key, value in init_strategies.items()
        }

        self.symbols = [sym.Symbol for sym in manageData.data.values()]

        # self.base_contracts = max(1, min(self.Portfolio.TotalPortfolioValue // 200_000, 10))
        self.base_contracts = self.GetBaseContracts()

        self.positions = pd.Series(0., index=self.symbols)

    
    def GetBaseContracts(self):
        return max(1, self.Portfolio.TotalPortfolioValue // 100_000)


    def OnData(self, data: Slice):

        # base_contracts = max(1, min(self.Portfolio.TotalPortfolioValue // 200_000, 10))
        base_contracts = self.GetBaseContracts()

        if base_contracts > self.base_contracts:
            self.base_contracts = base_contracts
        
        positions = pd.Series(0., index=self.symbols)

        for strategy in self.Strategies.values():
            if data.ContainsKey(strategy.symbol):
                strategy.CreateSignals(data)
                positions[strategy.symbol] += int(strategy.position * self.base_contracts * strategy.strategy_weight)
            else:
                positions[strategy.symbol] = self.positions[strategy.symbol]

        new_positions = {}

        for sym, pos in positions.items():
            current = self.Portfolio[sym].Quantity
            if abs(pos) < abs(current) and self.CurrentSlice.ContainsKey(sym) and self.CurrentSlice[sym] is not None:
                order_quantity = pos - current
                self.MarketOrder(sym, order_quantity, True)
            elif abs(pos) > abs(current):
                order_quantity = pos - current
                new_positions[sym] = order_quantity

        for sym, order_quantity in new_positions.items():
            if  self.CurrentSlice.ContainsKey(sym) and self.CurrentSlice[sym] is not None:
                self.MarketOrder(sym, order_quantity, True)

        self.positions = positions.copy()

#region imports
from AlgorithmImports import *
#endregion


class CLSpreadFeeModel(FeeModel):

    IB_BASE_FEE = 0.85 * 2
    EXCHANGE_FEE = 3.84
    REGULATORY_FEE = 0.02

    def __init__(self):
        super().__init__()

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        order_quantity = parameters.Order.AbsoluteQuantity
        fee = (self.IB_BASE_FEE + self.EXCHANGE_FEE + self.REGULATORY_FEE) * order_quantity
        return OrderFee(CashAmount(fee, 'USD'))


class BRSpreadFeeModel(FeeModel):

    IB_BASE_FEE = 0.85 * 2
    EXCHANGE_FEE = 2.44
    REGULATORY_FEE = 0.02

    def __init__(self):
        super().__init__()

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        order_quantity = parameters.Order.AbsoluteQuantity
        fee = (self.IB_BASE_FEE + self.EXCHANGE_FEE + self.REGULATORY_FEE) * order_quantity
        return OrderFee(CashAmount(fee, 'USD'))


class ArbSpreadFeeModel(FeeModel):

    IB_BASE_FEE = 0.85 * 4
    EXCHANGE_FEE = 3.84 + 2.44
    REGULATORY_FEE = 0.02

    def __init__(self):
        super().__init__()

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        order_quantity = parameters.Order.AbsoluteQuantity
        fee = (self.IB_BASE_FEE + self.EXCHANGE_FEE + self.REGULATORY_FEE) * order_quantity
        return OrderFee(CashAmount(fee, 'USD'))

class ClOutrightFeeModel(FeeModel):

    IB_BASE_FEE = 0.85
    EXCHANGE_FEE = 1.22
    REGULATORY_FEE = 0.02

    def __init__(self):
        super().__init__()

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        order_quantity = parameters.Order.AbsoluteQuantity
        fee = (self.IB_BASE_FEE + self.EXCHANGE_FEE + self.REGULATORY_FEE) * order_quantity
        return OrderFee(CashAmount(fee, 'USD'))

class BrOutrightFeeModel(FeeModel):

    IB_BASE_FEE = 0.85
    EXCHANGE_FEE = 1.92
    REGULATORY_FEE = 0.02

    def __init__(self):
        super().__init__()

    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        order_quantity = parameters.Order.AbsoluteQuantity
        fee = (self.IB_BASE_FEE + self.EXCHANGE_FEE + self.REGULATORY_FEE) * order_quantity
        return OrderFee(CashAmount(fee, 'USD'))
#region imports
from AlgorithmImports import *
from base_classes.Strategy import Strategy
from data.data_utils import GetRollDates
from strategy_utils import StrategyParameters
#endregion


# Your New Python File
class ArbSpreadStrategy(Strategy):

    def __init__(self, algo: QCAlgorithm, symbol, contract, strategy_parameters: StrategyParameters, **kwargs):
        super().__init__(algo)
        self.contract = contract
        self.symbol = contract.Symbol

        roll_dates = GetRollDates(symbol)

        self.roll_dates = [datetime.strptime(d, '%Y-%m-%d').date() for d in roll_dates]

        self.strategy_weight = strategy_parameters.strategy_weight

        self.long_stop = strategy_parameters.long_stop_loss
        self.initial_long = strategy_parameters.initial_long_entry
        self.longs_step = strategy_parameters.long_entry_step
        self.longs_profit_target = strategy_parameters.long_profit_target

        self.short_stop = strategy_parameters.short_stop_loss
        self.initial_short = strategy_parameters.initial_short_entry
        self.shorts_step = strategy_parameters.short_entry_step
        self.shorts_profit_target = strategy_parameters.short_profit_target

        self.long_entries = [ x / 100 for x in range(self.initial_long, self.long_stop, self.longs_step) ]
        self.short_entries = [ x / 100 for x in range(self.initial_short, self.short_stop, self.shorts_step) ]

        self.rolled_date = None
        self.stopped_out = False
        self.reset_stopped_date = None


    def CreateSignals(self, data: Slice):
        
        if self.algo.CurrentSlice.ContainsKey(self.symbol) and self.algo.CurrentSlice[self.symbol] is not None:
            custom_data = data[self.symbol]
            close = custom_data.Close
            
            previous_position = self.position

            if self.algo.Time.date() in self.roll_dates:
                if self.position != 0:
                    self.position = 0
                return

            # If contracts have rolled, reset stopped_out flag
            roll_months = [
                x.month for x in self.roll_dates 
                if x.year == self.algo.Time.year
                ]

            roll_day = [
                x for x in self.roll_dates 
                if (x.year == self.algo.Time.year or x.year == self.algo.Time.year - 1) 
                and x.month <= self.algo.Time.month
                ]


            if len(roll_day) > 0:
                roll_day = max(roll_day)
                is_roll_date = self.algo.Time.month in roll_months and self.algo.Time.date() > roll_day \
                    and (self.rolled_date is None or self.rolled_date.month != self.algo.Time.month or self.rolled_date.year != self.algo.Time.year)
            else:
                is_roll_date = False


            if is_roll_date:
                self.rolled_date = self.algo.Time
                self.reset_stopped_date = self.algo.Time

            if self.stopped_out and self.reset_stopped_date is not None and self.algo.Time.date() > self.reset_stopped_date.date():
                self.reset_stopped_date = None
                self.stopped_out = False


            # If spread is outside of range, stop out
            if (close > self.short_stop / 100 or close <  self.long_stop / 100) and not self.stopped_out:
                self.stopped_out = True
                self.position = 0
            
            # If stopped out, don't trade
            if self.stopped_out:
                return

            # Get number of entries triggered for longs and shorts
            num_long_entries = len([ entry for entry in self.long_entries if close < entry ])
            num_short_entries = len([ entry for entry in self.short_entries if close > entry ])

            num_long_entires_targets = len([ entry for entry in self.long_entries if close < entry + abs(self.longs_profit_target / 100) and close >= entry])
            num_short_entries_targets = len([ entry for entry in self.short_entries if close > entry - abs(self.shorts_profit_target / 100) and close <= entry])

            total_longs = num_long_entries + num_long_entires_targets if abs(previous_position) > abs(num_long_entries) else num_long_entries
            total_shorts = num_short_entries + num_short_entries_targets if abs(previous_position) > abs(num_short_entries) else num_short_entries

            if total_longs > 0:
                self.position = total_longs
            elif total_shorts > 0:
                self.position = -total_shorts
            elif self.position != 0:
                self.position = 0
#region imports
from AlgorithmImports import *
from base_classes.Strategy import Strategy
from data.data_utils import GetRollDates
from strategy_utils import StrategyParameters
#endregion


# Your New Python File
class CalendarSpreadStrategy(Strategy):

    def __init__(self, algo: QCAlgorithm, symbol, contract, strategy_parameters: StrategyParameters, **kwargs):
        super().__init__(algo)
        self.contract = contract
        self.symbol = contract.Symbol

        roll_dates = GetRollDates(symbol)

        self.roll_dates = [datetime.strptime(d, '%Y-%m-%d').date() for d in roll_dates]

        self.strategy_weight = strategy_parameters.strategy_weight

        self.long_stop = strategy_parameters.long_stop_loss
        self.initial_long = strategy_parameters.initial_long_entry
        self.longs_step = strategy_parameters.long_entry_step
        self.longs_profit_target = strategy_parameters.long_profit_target

        self.short_stop = strategy_parameters.short_stop_loss
        self.initial_short = strategy_parameters.initial_short_entry
        self.shorts_step = strategy_parameters.short_entry_step
        self.shorts_profit_target = strategy_parameters.short_profit_target

        self.long_entries = [ x / 100 for x in range(self.initial_long, self.long_stop, self.longs_step) ]
        self.short_entries = [ x / 100 for x in range(self.initial_short, self.short_stop, self.shorts_step) ]

        self.stopped_out = False
        self.rolled_date = None
        self.reset_stopped_date = None

    def CreateSignals(self, data: Slice):

        if self.algo.CurrentSlice.ContainsKey(self.symbol) and self.algo.CurrentSlice[self.symbol] is not None:
            custom_data = data[self.symbol]
            close = custom_data.Close
            
            previous_position = self.position

            if self.algo.Time.date() in self.roll_dates:
                if self.algo.Portfolio.Invested:
                    self.position = 0
                return

            # If contracts have rolled, reset stopped_out flag
            roll_months = [
                x.month for x in self.roll_dates 
                if x.year == self.algo.Time.year
                ]

            roll_day = [
                x for x in self.roll_dates 
                if (x.year == self.algo.Time.year or x.year == self.algo.Time.year - 1) 
                and x.month <= self.algo.Time.month
                ]


            if len(roll_day) > 0:
                roll_day = max(roll_day)
                is_roll_date = self.algo.Time.month in roll_months and self.algo.Time.date() > roll_day \
                    and (self.rolled_date is None or self.rolled_date.month != self.algo.Time.month or self.rolled_date.year != self.algo.Time.year)
            else:
                is_roll_date = False


            if is_roll_date:
                self.rolled_date = self.algo.Time
                self.reset_stopped_date = self.algo.Time

            if self.stopped_out and self.reset_stopped_date is not None and self.algo.Time.date() > self.reset_stopped_date.date():
                self.reset_stopped_date = None
                self.stopped_out = False

            # If spread is outside of 5 point range, stop out
            if (close > self.short_stop / 100 or close <  self.long_stop / 100) and not self.stopped_out:
                self.stopped_out = True
                self.position = 0
            
            # If stopped out, don't trade
            if self.stopped_out:
                return

            # Get number of entries triggered for longs and shorts
            num_long_entries = len([ entry for entry in self.long_entries if close < entry ])
            num_short_entries = len([ entry for entry in self.short_entries if close > entry ])

            num_long_entires_targets = len([ entry for entry in self.long_entries if close < entry + abs(self.longs_profit_target / 100) and close >= entry])
            num_short_entries_targets = len([ entry for entry in self.short_entries if close > entry - abs(self.shorts_profit_target / 100) and close <= entry])

            total_longs = num_long_entries + num_long_entires_targets if abs(previous_position) > abs(num_long_entries) else num_long_entries
            total_shorts = num_short_entries + num_short_entries_targets if abs(previous_position) > abs(num_short_entries) else num_short_entries

            if total_longs > 0:
                self.position = total_longs
            elif total_shorts > 0:
                self.position = -total_shorts
            elif self.position != 0:
                self.position = 0
#region imports
from AlgorithmImports import *
from base_classes.Strategy import Strategy
from data.data_utils import GetRollDates
from strategy_utils import DmaStrategyParameters
#endregion


# Your New Python File
class DailyMovingAverageStrategy(Strategy):

    def __init__(self, algo: QCAlgorithm, symbol, contract, strategy_parameters: DmaStrategyParameters, is_monthly_rolls=False, **kwargs):
        super().__init__(algo)
        self.contract = contract
        self.symbol = contract.Symbol

        self.strategy_weight = strategy_parameters.strategy_weight

        self.long_fast_ema = algo.EMA(
            self.symbol, 
            strategy_parameters.long_fast, 
            Resolution.Daily
            )

        self.long_slow_ema = algo.EMA(
            self.symbol, 
            strategy_parameters.long_slow, 
            Resolution.Daily
            )

        self.short_fast_ema = algo.EMA(
            self.symbol, 
            strategy_parameters.short_fast, 
            Resolution.Daily
            )

        self.short_slow_ema = algo.EMA(
            self.symbol, 
            strategy_parameters.short_slow, 
            Resolution.Daily
            )

        self.tolerance = strategy_parameters.tolerance

        roll_dates = GetRollDates(symbol)

        self.roll_dates = [datetime.strptime(d, '%Y-%m-%d').date() for d in roll_dates]

        self.stopped_out = False
        self.rolled_date = None

    def CreateSignals(self, data: Slice):

        if self.algo.CurrentSlice.ContainsKey(self.symbol) and self.algo.CurrentSlice[self.symbol] is not None:
            custom_data = data[self.symbol]
            close = custom_data.Close
            
            previous_position = self.position

            if self.algo.Time.date() in self.roll_dates:
                if self.algo.Portfolio.Invested:
                    self.position = 0
                return

            if self.stopped_out and self.algo.Time.date() in self.roll_dates:
                self.stopped_out = False
            
            # If stopped out, don't trade
            if (self.stopped_out 
                or not self.long_fast_ema.IsReady or not self.long_slow_ema.IsReady 
                or not self.short_fast_ema.IsReady or not self.short_slow_ema.IsReady):
                return

            long_fast_ema = self.long_fast_ema.Current.Value
            long_slow_ema = self.long_slow_ema.Current.Value
            short_fast_ema = self.short_fast_ema.Current.Value
            short_slow_ema = self.short_slow_ema.Current.Value

            is_long = self.position > 0
            is_short = self.position < 0

            long_entry = not is_long and not is_short and long_fast_ema > long_slow_ema * (1 + self.tolerance)
            long_exit = is_long and long_fast_ema < long_slow_ema

            short_entry = not is_long and not is_short and short_fast_ema < short_slow_ema * (1 + self.tolerance)
            short_exit = is_short and short_fast_ema > short_slow_ema

            if long_exit or short_exit:
                self.position = 0
            elif long_entry and not short_entry:
                self.position = 1
            elif short_entry and not long_entry:
                self.position = -1
            else:
                self.position = previous_position
#region imports
from AlgorithmImports import *
from base_classes.Strategy import Strategy
from data.data_utils import GetRollDates
from strategy_utils import StrategyParameters
#endregion


# Your New Python File
class CalendarDivisionSpreadStrategy(Strategy):

    def __init__(self, algo: QCAlgorithm, symbol, contract, strategy_parameters: StrategyParameters, signal_contract = None, **kwargs):
        super().__init__(algo)
        self.contract = contract
        self.symbol = contract.Symbol

        self.signal_contract = signal_contract
        self.signal_symbol = signal_contract.Symbol

        roll_dates = GetRollDates(symbol)

        self.roll_dates = [datetime.strptime(d, '%Y-%m-%d').date() for d in roll_dates]

        self.strategy_weight = strategy_parameters.strategy_weight

        self.long_stop = strategy_parameters.long_stop_loss
        self.initial_long = strategy_parameters.initial_long_entry
        self.longs_step = strategy_parameters.long_entry_step
        self.longs_profit_target = strategy_parameters.long_profit_target

        self.short_stop = strategy_parameters.short_stop_loss
        self.initial_short = strategy_parameters.initial_short_entry
        self.shorts_step = strategy_parameters.short_entry_step
        self.shorts_profit_target = strategy_parameters.short_profit_target

        self.adjustment = 1000

        self.long_entries = [ x / self.adjustment for x in range(self.initial_long, self.long_stop, self.longs_step) ]
        self.short_entries = [ x / self.adjustment for x in range(self.initial_short, self.short_stop, self.shorts_step) ]

        self.stopped_out = False
        self.rolled_date = None
        self.reset_stopped_date = None

        self.max_contract_risk = 1

        self.division_spread = None

        self.max_range = 1.25
        self.min_range = 0.85


    def get_max_contracts(self, traded_spread, division_spread):
        max_risk_percent = 2
        portfolio_value = self.algo.Portfolio.TotalPortfolioValue
        value_per_point = 100

        if division_spread < 1:
            max_spread_risk = (abs(traded_spread) / (1 - division_spread)) * self.min_range
        elif division_spread > 1:
            max_spread_risk = (abs(traded_spread) / (division_spread - 1)) * self.max_range
        else:
            return 1

        current_spread_risk_per_point = max(value_per_point, abs(max_spread_risk) * value_per_point)
        return round((portfolio_value * max_risk_percent) / current_spread_risk_per_point)


    def get_signal_confidence(self, division_spread):
        if division_spread < 0.99:
            return (0.99 - division_spread) / (self.min_range - 0.99)
        elif division_spread > 1.01:
            return (division_spread - 1.01) / (1.01 - self.max_range)
        else:
            return 0


    def CreateSignals(self, data: Slice):

        # if self.algo.CurrentSlice.ContainsKey(self.signal_symbol) and self.algo.CurrentSlice[self.signal_symbol] is not None:
        #         self.division_spread = data[self.signal_symbol].Close

        if self.algo.CurrentSlice.ContainsKey(self.signal_symbol) and self.algo.CurrentSlice[self.signal_symbol] is not None:

            custom_data = data[self.signal_symbol]
            close = custom_data.Close
            
            previous_position = self.position

            if self.algo.Time.date() in self.roll_dates:
                if self.algo.Portfolio.Invested:
                    self.position = 0
                return

            # If contracts have rolled, reset stopped_out flag
            roll_months = [
                x.month for x in self.roll_dates 
                if x.year == self.algo.Time.year
                ]

            roll_day = [
                x for x in self.roll_dates 
                if (x.year == self.algo.Time.year or x.year == self.algo.Time.year - 1) 
                and x.month <= self.algo.Time.month
                ]


            if len(roll_day) > 0:
                roll_day = max(roll_day)
                is_roll_date = self.algo.Time.month in roll_months and self.algo.Time.date() > roll_day \
                    and (self.rolled_date is None or self.rolled_date.month != self.algo.Time.month or self.rolled_date.year != self.algo.Time.year)
            else:
                is_roll_date = False
                

            if is_roll_date:
                self.rolled_date = self.algo.Time
                self.reset_stopped_date = self.algo.Time

            if self.stopped_out and self.reset_stopped_date is not None and self.algo.Time.date() > self.reset_stopped_date.date():
                self.reset_stopped_date = None
                self.stopped_out = False

            # If spread is outside of 5 point range, stop out
            if (close > self.short_stop / self.adjustment or close < self.long_stop / self.adjustment) and not self.stopped_out:
                self.stopped_out = True
                self.position = 0
            
            # If stopped out, don't trade
            if self.stopped_out:
                return

            # Get number of entries triggered for longs and shorts
            num_long_entries = len([ entry for entry in self.long_entries if close < entry ])
            num_short_entries = len([ entry for entry in self.short_entries if close > entry ])

            num_long_entires_targets = len([ 
                entry for entry in self.long_entries 
                if close < entry + abs(self.longs_profit_target / 100) and close >= entry
                ])

            num_short_entries_targets = len([ 
                entry for entry in self.short_entries 
                if close > entry - abs(self.shorts_profit_target / 100) and close <= entry
                ])

            total_longs = num_long_entries + num_long_entires_targets \
                if abs(previous_position) > abs(num_long_entries) else num_long_entries

            total_shorts = num_short_entries + num_short_entries_targets \
                if abs(previous_position) > abs(num_short_entries) else num_short_entries

            """
            If traded spread is at 2
            Division spread is at 1.25
            We can maximise number of contracts traded

            If traded spread is at 2
            Division spread is at 1.10
            We need to trade a reduced number of contracts as the spread could widen further

            Based on current traded spread we can determine where the spread would be at the extremes
            """

            # if self.division_spread != 0:
            #     average_price = traded_spread / (self.division_spread - 1)
            # else:
            #     self.position = 0
            #     return

            # max_spread = average_price * (self.max_range - 1)
            # min_spread = average_price * (1 - self.min_range)

            # upper_risk = int(self.algo.TotalPortfolioValue / (max_spread * 100))
            # lower_risk = int(self.algo.TotalPortfolioValue / (min_spread * 100))
            
            if total_longs > 0:
                self.position = total_longs
            elif total_shorts > 0:
                self.position = -total_shorts
            elif self.position != 0:
                self.position = 0

            # if close < 0.99:
            #     position = max(1, int(self.get_signal_confidence(close) * self.max_contract_risk))
            #     if abs(position) > self.position:
            #         self.position = position
            # elif close > 1.01:
            #     position = -abs(max(1, int(self.get_signal_confidence(close) * self.max_contract_risk)))
            #     if position < self.position:
            #         self.position = position
            # else:
            #     self.position = 0
#region imports
from AlgorithmImports import *
#endregion

class StrategyInitialiser():

    def __init__(self, strategy, symbol, strategy_parameters, **kwargs):

        self.STRATEGY = strategy
        self.SYMBOL = symbol
        self.STRATEGY_PARAMETERS = strategy_parameters
        self.STRATEGY_OPTIONS = kwargs


class StrategyParameters():

    def __init__(self, 
        initial_long_entry, long_entry_step, long_stop_loss, long_profit_target,
        initial_short_entry, short_entry_step, short_stop_loss, short_profit_target,
        strategy_weight = 1
        ):

        self.initial_long_entry = initial_long_entry
        self.long_entry_step = long_entry_step
        self.long_stop_loss = long_stop_loss
        self.long_profit_target, = long_profit_target,
        self.initial_short_entry = initial_short_entry
        self.short_entry_step = short_entry_step
        self.short_stop_loss = short_stop_loss
        self.short_profit_target = short_profit_target

        self.strategy_weight = strategy_weight


class DmaStrategyParameters():

    def __init__(self, 
        long_fast = 10, long_slow = 30, short_fast = 1, short_slow = 3, 
        tolerance = 0.00015, strategy_weight = 1
        ):

        self.long_fast = long_fast
        self.long_slow = long_slow
        self.short_fast = short_fast
        self.short_slow = short_slow
        self.tolerance = tolerance

        self.strategy_weight = strategy_weight