Overall Statistics |
Total Trades 686 Average Win 0.84% Average Loss -0.72% Compounding Annual Return -0.716% Drawdown 24.000% Expectancy -0.021 Net Profit -7.386% Sharpe Ratio -0.061 Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.16 Alpha -0.003 Beta -0.004 Annual Standard Deviation 0.056 Annual Variance 0.003 Information Ratio -0.701 Tracking Error 0.148 Treynor Ratio 0.96 Total Fees $0.00 |
class RiskPremiaForexAlgorithm(QCAlgorithm): ''' Asymmetric Tail Risks and Excess Returns in Forex Markets Paper: https://arxiv.org/pdf/1409.7720.pdf ''' def Initialize(self): self.SetStartDate(2009, 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 for pair in ['EURUSD', 'AUDUSD', 'USDCAD', 'USDJPY']: self.AddForex(pair, Resolution.Hour, Market.FXCM) 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 pair is less than this level, enter a long postion self.shortSkewLevel = 0.6 # If the skewness of a pair 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 # Get historical close data for the symbols history = self.History(self.Securities.Keys, self.lookback, Resolution.Daily) history = history.drop_duplicates().close.unstack(level=0) # Get the skewness of the historical data skewness = self.GetSkewness(history) longSymbols = [k for k,v in skewness.items() if v < self.longSkewLevel] shortSymbols = [k for k,v in skewness.items() if v > self.shortSkewLevel] # Liquidate the holdings for pairs that will not trade for holding in self.Portfolio.Values: symbol = holding.Symbol if holding.Invested and symbol.Value not in longSymbols + shortSymbols: self.Liquidate(symbol, 'Not selected pair') # Open positions for the symbols with equal weights count = len(longSymbols) + len(shortSymbols) for pair in longSymbols: self.SetHoldings(pair, 1/count) for pair in shortSymbols: self.SetHoldings(pair, -1/count) # Set next rebalance time self.nextRebalance += timedelta(self.rebalanceDays) def GetSkewness(self, values): ''' Get the skewness for all forex symbols based on its historical data Ref: https://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm ''' # Get the numerator of the skewness numer = ((values - values.mean()) ** 3).sum() # Get the denominator of the skewness denom = self.lookback * values.std() ** 3 # Return the skewness return (numer/denom).to_dict()