Overall Statistics |
Total Trades 102 Average Win 0.31% Average Loss -0.47% Compounding Annual Return -5.581% Drawdown 5.500% Expectancy -0.166 Net Profit -3.766% Sharpe Ratio -0.763 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.67 Alpha -0.027 Beta -0.063 Annual Standard Deviation 0.05 Annual Variance 0.003 Information Ratio -1.641 Tracking Error 0.132 Treynor Ratio 0.607 Total Fees $0.00 |
class RiskPremiaForexAlgorithm(QCAlgorithm): ''' Asymmetric Tail Risks and Excess Returns in Forex Market Paper: https://arxiv.org/pdf/1409.7720.pdf ''' def Initialize(self): self.SetStartDate(2019, 1, 1) # Set Start Date self.SetEndDate(2019, 9, 1) # Set End Date self.SetCash(100000) # Set Strategy Cash # Add forex data of the following symbols forexs = ["EURUSD", "AUDUSD", "USDCAD", "USDJPY"] self.symbols = [self.AddForex(forex, Resolution.Hour, Market.FXCM).Symbol for forex in forexs] self.lookback = 30 # Length(days) of historical data self.nextRebalance = self.Time # Next time to rebalance self.rebalanceDays = 7 # Rebalance every 7 days (weekly) self.longSkewLevel = -0.6 # If the skewness of a forex is less than this level, enter a long postion self.shortSkewLevel = 0.6 # If the skewness of a froex is larger than this level, enter a short position def OnData(self, data): ''' Rebalance weekly for each forex pair ''' # Do nothing until next rebalance if self.Time < self.nextRebalance: return # Liquidate the holdings when the rebalance day comes for holding in self.Portfolio.Values: if holding.Invested: self.Liquidate(holding.Symbol,"Liquidate") # Get historical close data for the symbols history = self.History(self.symbols, self.lookback, Resolution.Daily).close.unstack(level=0) # The lists containing symbols for long & short longSymbols = [] shortSymbols = [] # Get skewness for each symbol for forex in self.symbols: skewness = self.GetSkewness(history[str(forex)].values) # If the skewness of a forex is less than the longSkew level, # put this symbol into the longSymbols list if skewness < self.longSkewLevel: longSymbols.append(forex) # If the skewness of a forex is larger than the shortSkew level, # put this symbol into the shortSymbols list if skewness > self.shortSkewLevel: shortSymbols.append(forex) # Open positions for the symbols with equal weights count = len(longSymbols) + len(shortSymbols) # If no suitable symbols, return if count == 0: return # Long positions for forex in longSymbols: self.SetHoldings(forex, 1/count) # Short postions for forex in shortSymbols: self.SetHoldings(forex, -1/count) # Set next rebalance time self.nextRebalance += timedelta(self.rebalanceDays) def GetSkewness(self, values): ''' Get the skewness for a forex symbol based on its historical data Ref: https://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm ''' # Get standard deviation of the values sd = values.std() # Get the numerator of the skewness numer = ((values - values.mean()) ** 3).sum() # Get the denominator of the skewness denom = self.lookback * sd ** 3 # Return the skewness return numer/denom