Overall Statistics
Total Trades
10200
Average Win
0.03%
Average Loss
-0.03%
Compounding Annual Return
1.046%
Drawdown
4.000%
Expectancy
0.121
Net Profit
20.098%
Sharpe Ratio
0.751
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.11
Alpha
0.01
Beta
-0.005
Annual Standard Deviation
0.013
Annual Variance
0
Information Ratio
-0.422
Tracking Error
0.181
Treynor Ratio
-1.975
Total Fees
$0.00
 
 
from datetime import datetime
import numpy as np
from collections import deque
import math

class TOM_Effect_Futures(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2002, 1, 1)
        self.SetEndDate(2019, 8, 1)
        self.SetCash(100000)

        self.symbols = ["CHRIS/CME_BP1", # British Pound Futures, Continuous Contract #1
                    "CHRIS/CME_EC1", # Euro FX Futures, Continuous Contract #1
                    "CHRIS/CME_SF1", # Swiss Franc Futures, Continuous Contract #1
                    "CHRIS/CME_CD1", # Canadian Dollar Futures, Continuous Contract #1
                    "CHRIS/CME_AD1", # Australian Dollar Futures, Continuous Contract #1
                    "CHRIS/CME_JY1", # Japanese Yen Futures, Continuous Contract #1
                    
                    "CHRIS/ICE_DX1", # US Dollar Index Futures, Continuous Contract #1
                    
                    "CHRIS/LIFFE_FCE1", # CAC40 Index Futures, Continuous Contract #1
                    "CHRIS/CME_ES1", # E-mini S&P 500 Futures, Continuous Contract #1
                    "CHRIS/EUREX_FSTX1", # STOXX Europe 50 Index Futures, Continuous Contract #1
                    "CHRIS/EUREX_FSMI1", # SMI Futures, Continuous Contract #1
                    "CHRIS/LIFFE_Z1", # FTSE 100 Index Futures, Continuous Contract #1
                    "CHRIS/CME_NQ1", # E-mini NASDAQ 100 Futures, Continuous Contract #1
   
                    "CHRIS/CME_TY1", # 10 Yr Note Futures, Continuous Contract #1 (USA)
                    "CHRIS/CME_FV1", # 5 Yr Note Futures, Continuous Contract #1 (USA)
                    "CHRIS/CME_TU1", # 2 Yr Note Futures, Continuous Contract #1 (USA)
                    "CHRIS/EUREX_FGBL1", # Euro-Bund (10Y) Futures, Continuous Contract #1 (Germany)
                    "CHRIS/LIFFE_R1", # Long Gilt Futures, Continuous Contract #1 (U.K.)
                    "CHRIS/EUREX_FOAT1", # Euro-OAT Futures, Continuous Contract #1 (France)                
                    "CHRIS/EUREX_FBTP1", # Long-Term Euro-BTP Futures, Continuous Contract #1 (Italy)

                    "CHRIS/CME_S1", # Soybean Futures, Continuous Contract #1
                    "CHRIS/CME_W1", # Wheat Futures, Continuous Contract #1
                    "CHRIS/CME_SM1", # Soybean Meal Futures, Continuous Contract #1
                    "CHRIS/CME_BO1", # Soybean Oil Futures, Continuous Contract #1
                    "CHRIS/CME_LC1", # Live Cattle Futures, Continuous Contract #1 
                    "CHRIS/CME_FC1", # Feeder Cattle Futures, Continuous Contract #1
                    "CHRIS/CME_GC1", # Gold Futures, Continuous Contract #1 
                    "CHRIS/CME_PL1", # Platinum Futures, Continuous Contract #1
                    "CHRIS/CME_HG1", # Copper Futures, Continuous Contract #1
                    "CHRIS/CME_CL1", # Crude Oil Futures, Continuous Contract #1
                    "CHRIS/ICE_CT1", # Cotton No. 2 Futures, Continuous Contract
                    "CHRIS/ICE_OJ1", # Orange Juice Futures, Continuous Contract
                    "CHRIS/ICE_KC1", # Coffee C Futures, Continuous Contract
                    "CHRIS/ICE_CC1", # Cocoa Futures, Continuous Contract
        ]
        
        self.data = {}
        
        ma_period = 100
        vol_period = 60
        self.SetWarmUp(vol_period)
        
        self.days = 0
        self.month_turn = False
        
        for symbol in self.symbols:
            data = self.AddData(QuandlFutures, symbol, Resolution.Daily)
            #data.SetLeverage(2)
            ma = self.SMA(symbol, ma_period, Resolution.Daily)
            self.data[symbol] = SymbolData(symbol, vol_period, ma)
        
        self.AddEquity('SPY', Resolution.Daily)
        self.Schedule.On(self.DateRules.MonthEnd('SPY'), self.TimeRules.AfterMarketOpen('SPY'), self.Purchase)
    
    def OnData(self, data):
        for symbol in self.symbols:
            if self.Securities.ContainsKey(symbol):
                price = self.Securities[symbol].Price
                if not (math.isnan(price) or price == 0):
                    self.data[symbol].Update(price)
        
        if self.IsWarmingUp: return
        if self.month_turn:
            self.days += 1
            if self.days == 3:
                self.Liquidate()
                self.month_turn = False
                self.days = 0
            
    def Purchase(self):
        if self.IsWarmingUp: return
        
        # MA sorting
        long = list(data for data in self.data.items() if data[1].Price > data[1].MA.Current.Value)
        short = list(data for data in self.data.items() if data[1].Price < data[1].MA.Current.Value)
        
        # Weighting
        total_vol = sum((1.0/data[1].Volatility()) for data in long if data[1].IsReady()) + sum((1.0/data[1].Volatility()) for data in short if data[1].IsReady())
        for data in long + short:
            if data[1].IsReady():
                vol = data[1].Volatility()
                data[1].Weight = (1.0 / vol) / total_vol

        for data in long:
            if data[1].Weight != 0:
                self.SetHoldings(data[0], data[1].Weight)
        for data in short:
            if data[1].Weight != 0:
                self.SetHoldings(data[0], -(data[1].Weight))
        
        self.month_turn = True

class SymbolData:
    def __init__(self, symbol, volatility_lookback, ma):
        self.Symbol = symbol
        self.History = deque(maxlen=volatility_lookback)
        self.MA = ma
        self.Price = 0.0
        self.Weight = 0.0

    def IsReady(self):
        return len(self.History) == self.History.maxlen
        
    def Update(self, value):
        self.Price = value
        self.History.append(float(value))

    def Volatility(self):
        prices = np.array(self.History)
        returns = (prices[1:]-prices[:-1])/prices[:-1]
        return np.std(returns)
    
class QuandlFutures(PythonQuandl):
    def __init__(self):
        self.ValueColumnName = "Settle"