Overall Statistics
Total Trades
994
Average Win
0.94%
Average Loss
-0.22%
Compounding Annual Return
8.268%
Drawdown
50.200%
Expectancy
1.764
Net Profit
340.364%
Sharpe Ratio
0.392
Probabilistic Sharpe Ratio
0.062%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
4.22
Alpha
0.031
Beta
0.88
Annual Standard Deviation
0.197
Annual Variance
0.039
Information Ratio
0.175
Tracking Error
0.143
Treynor Ratio
0.088
Total Fees
$3022.64
Estimated Strategy Capacity
$1000000.00
Lowest Capacity Asset
ERUS URI1LRYQ5ISL
#region imports
from AlgorithmImports import *
#endregion

class ValueEffectWithinCountries(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2000, 1, 8)   # Set Start Date
        self.SetEndDate(2018, 9, 1)     # Set End Date
        self.SetCash(100000)            # Set Strategy Cash
        self.symbol = self.AddData(CAPE, "CAPE", Resolution.Daily).Symbol

        self.symbols = Symbols().tickers
        for key, value in self.symbols.items():
            self.AddEquity(value[1], Resolution.Daily)  
        
    def OnData(self, data):
        if data.ContainsKey(self.symbol):
            cape = {}
            for key, value in self.symbols.items(): 
                cape[value[1]] = data[self.symbol].GetProperty(key)

            sorted_cape = sorted(cape, key = lambda x: cape[x])
            
            # invests the cheapest 33% of countries if those countries have a CAPE below 15
            lowest_cape = sorted_cape[:int(1/3*len(sorted_cape))]
            long_list = [i for i in lowest_cape if cape[i] < 15]
            invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            
            for i in invested:
                if i.Value not in long_list:
                    self.Liquidate(i)
            
            for i in long_list:
                self.SetHoldings(i, 1/len(long_list))
                    

class CAPE(PythonData):

    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://indices.cib.barclays/file.app?action=shared&path=shiller/cape.csv", SubscriptionTransportMedium.RemoteFile)

    def Reader(self, config, line, date, isLiveMode):
        if not (line.strip() and line[1].replace('.', '', 1).isdigit()): return None

        try:
            index = CAPE()
            index.Symbol = config.Symbol
            
            data = line.split(',')
            index.Time = datetime.strptime(data[0], "%d/%m/%Y")
            symbols = Symbols().tickers
            for key, value in symbols.items():
                index[key] = float(data[value[0]]) if data[value[0]] else 100000 # very large number to avoid be selected
            return index

        except:
            return None


class Symbols:
    def __init__(self):
        # the indiex is the country name
        # the first element of the value is the column number of CAPE ratio value in custom dataset
        # the second element of the value is the corresponding country ETF
        
        self.tickers = {"Australia":[1, "EWA"],       # ASX All Ordinaries Index: iShares MSCI Australia ETF
                        "Brazil":[2, "EWZ"],          # Indice Bovespa (Ibovespa): iShares MSCI Brazil ETF
                        "Canada":[3, "XIC"],          # S&P/TSX Composite Index: iShares S&P TSX Capped Cmpst Indx Fnd
                        "China":[4, "MCHI"],          # SSE Composite: iShares MSCI China Index Fund
                        "Europe":[5, "IEUR"],         # STOXX Europe 600 Index: iShares Core MSCI Europe ETF
                        "France":[6, "EWQ"],          # CAC 40 Index: iShares MSCI France ETF
                        "Germany":[7, "EWG"],         # HDAX Index: iShares MSCI Germany ETF
                        "Hong Kong":[8, "EWH"],       # Hang Seng Index: iShares MSCI Hong Kong Index Fund
                        "Italy":[9, "EWI"],           # FTSE MIB Index: iShares MSCI Italy ETF
                        "India":[10, "INDY"],         # NIFTY 50 Index: iShares India 50 ETF
                        "Israel":[11, "EIS"],         # Tel Aviv 125 Index: iShares MSCI Israel ETF
                        "Japan":[12, "EWJ"],          # All Public Companies: iShares MSCI Japan ETF
                        "Korea":[13,"EWY"],           # KOSPI Index: iShares MSCI South Korea ETF
                        "Mexico":[14, "EWW"],         # &P/BMV IPC Index: iShares MSCI Mexico ETF
                        "Netherlands":[15, "EWN"],    # NL 25 Index: iShares MSCI Netherlands ETF
                        "Poland":[16, "EPOL"],        # WIG Index: iShares MSCI Poland ETF  
                        "Russia":[17, "ERUS"],        # RTS Index: iShares MSCI Russia ETF
                        "Singapore":[18, "EWS"],      # STI Index:  iShares MSCI Singapore ETF
                        "Southafrica":[19, "EZA"],    # FTSE/JSE CAP Top 40 Index: iShares MSCI South Africa ETF
                        "Spain":[20, "EWP"],          # IBEX 35 Index: iShares MSCI Spain ETF
                        "Sweden":[21, "EWD"],         # OMXS 30 index: iShares MSCI Sweden ETF
                        "Switzerland":[22, "EWL"],    # CH 20 index: iShares MSCI Switzerland ETF
                        "Taiwan":[23, "EWT"],         # TWSE: iShares MSCI Taiwan ETF
                        "Turkey":[24, "TUR"],         # BIST 100: iShares MSCI Turkey ETF
                        "UK":[25, "EWU"],             # FTSE 100 Index: iShares MSCI United Kingdom ETF
                        "USA":[26, "SPY"]            # S&P 500 Index: SPDR S&P 500 ETF 
        }