Overall Statistics |
Total Trades
1593
Average Win
0.59%
Average Loss
-0.77%
Compounding Annual Return
-0.161%
Drawdown
39.600%
Expectancy
0.007
Net Profit
-3.248%
Sharpe Ratio
0.021
Probabilistic Sharpe Ratio
0.000%
Loss Rate
43%
Win Rate
57%
Profit-Loss Ratio
0.77
Alpha
0.002
Beta
-0.013
Annual Standard Deviation
0.077
Annual Variance
0.006
Information Ratio
-0.31
Tracking Error
0.197
Treynor Ratio
-0.129
Total Fees
$1746.39
|
# https://quantpedia.com/strategies/currency-momentum-factor/ # # Create an investment universe consisting of several currencies (10-20). Go long three currencies with the highest 12-month momentum against USD # and go short three currencies with the lowest 12-month momentum against USD. Cash not used as margin invest on overnight rates. Rebalance monthly. from collections import deque import fk_tools from math import sqrt class Currency_Momentum_Factor(QCAlgorithm): def Initialize(self): self.SetStartDate(2000, 1, 1) self.SetCash(100000) # Daily close prices. self.data = {} self.period = 12 * 21 self.targeted_volatility = 0.10 self.symbols = [ "CME_AD1", # Australian Dollar Futures, Continuous Contract #1 "CME_BP1", # British Pound Futures, Continuous Contract #1 "CME_CD1", # Canadian Dollar Futures, Continuous Contract #1 "CME_EC1", # Euro FX Futures, Continuous Contract #1 "CME_JY1", # Japanese Yen Futures, Continuous Contract #1 "CME_MP1", # Mexican Peso Futures, Continuous Contract #1 "CME_NE1", # New Zealand Dollar Futures, Continuous Contract #1 "CME_SF1" # Swiss Franc Futures, Continuous Contract #1 ] for symbol in self.symbols: data = self.AddData(fk_tools.QuantpediaFutures, symbol, Resolution.Daily) data.SetFeeModel(fk_tools.CustomFeeModel(self)) data.SetLeverage(20) self.data[symbol] = deque(maxlen = self.period) self.Schedule.On(self.DateRules.MonthStart(self.symbols[0]), self.TimeRules.AfterMarketOpen(self.symbols[0]), self.Rebalance) def OnData(self, data): for symbol in self.symbols: if self.Securities.ContainsKey(symbol): price = self.Securities[symbol].Price if price != 0: self.data[symbol].append(price) else: # Append latest price as a next one in case there's 0 as price. if len(self.data[symbol]) > 0: last_price = self.data[symbol][-1] self.data[symbol].append(last_price) def Rebalance(self): # Store monthly closes and calculate momentum. momentum = {} volatility = {} for symbol in self.symbols: if len(self.data[symbol]) == self.data[symbol].maxlen: prices = [x for x in [x for x in self.data[symbol]]] momentum[symbol] = fk_tools.Return(prices) volatility[symbol] = fk_tools.Volatility(prices[-21:]) * sqrt(252) if len(momentum) == 0 or len(volatility) == 0: self.Liquidate() return sorted_by_momentum = sorted(momentum.items(), key = lambda x: x[1], reverse = True) long = [x[0] for x in sorted_by_momentum[:3]] short = [x[0] for x in sorted_by_momentum[-3:]] # Volatility targeting. count = len(long + short) portfolio_volatility = sum([((volatility[x]) / count) for x in long + short]) volatility_target_leverage = self.targeted_volatility / portfolio_volatility # Trade execution. invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested] for symbol in invested: if symbol not in long + short: self.Liquidate(symbol) for symbol in long: self.SetHoldings(symbol, volatility_target_leverage / len(long)) for symbol in short: self.SetHoldings(symbol, -volatility_target_leverage / len(short))
import numpy as np def Return(values): return (values[-1] - values[0]) / values[0] def Volatility(values): values = np.array(values) returns = (values[1:] - values[:-1]) / values[:-1] return np.std(returns) # Custom fee model class CustomFeeModel(FeeModel): def GetOrderFee(self, parameters): fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005 return OrderFee(CashAmount(fee, "USD")) # Quandl free data class QuandlFutures(PythonQuandl): def __init__(self): self.ValueColumnName = "settle" # Quantpedia data # NOTE: IMPORTANT: Data order must be ascending (datewise) class QuantpediaFutures(PythonData): def GetSource(self, config, date, isLiveMode): return SubscriptionDataSource("data.quantpedia.com/backtesting_data/futures/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv) def Reader(self, config, line, date, isLiveMode): data = QuantpediaFutures() data.Symbol = config.Symbol if not line[0].isdigit(): return None split = line.split(';') data.Time = datetime.strptime(split[0], "%d.%m.%Y") + timedelta(days=1) data['settle'] = float(split[1]) data.Value = float(split[1]) return data