Overall Statistics |
Total Orders
914
Average Win
0.17%
Average Loss
-0.19%
Compounding Annual Return
-0.033%
Drawdown
31.700%
Expectancy
-0.003
Start Equity
100000
End Equity
99168.12
Net Profit
-0.832%
Sharpe Ratio
-0.367
Sortino Ratio
-0.442
Probabilistic Sharpe Ratio
0.000%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
0.94
Alpha
-0.023
Beta
0.053
Annual Standard Deviation
0.058
Annual Variance
0.003
Information Ratio
-0.387
Tracking Error
0.16
Treynor Ratio
-0.401
Total Fees
$81.08
Estimated Strategy Capacity
$0
Lowest Capacity Asset
CME_AD1.QuantpediaFutures 2S
Portfolio Turnover
0.17%
|
#region imports from AlgorithmImports import * from dateutil.relativedelta import relativedelta #endregion # Quantpedia data. # NOTE: IMPORTANT: Data order must be ascending (datewise) class QuantpediaFutures(PythonData): _last_update_date:Dict[str, datetime.date] = {} @staticmethod def get_last_update_date() -> Dict[str, datetime.date]: return QuantpediaFutures._last_update_date 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['back_adjusted'] = float(split[1]) data['spliced'] = float(split[2]) data.Value = float(split[1]) # store last update date if config.Symbol.Value not in QuantpediaFutures._last_update_date: QuantpediaFutures._last_update_date[config.Symbol.Value] = datetime(1,1,1).date() if data.Time.date() > QuantpediaFutures._last_update_date[config.Symbol.Value]: QuantpediaFutures._last_update_date[config.Symbol.Value] = data.Time.date() return data class InterestRate3M(PythonData): _last_update_date:Dict[str, datetime.date] = {} @staticmethod def get_last_update_date() -> Dict[str, datetime.date]: return InterestRate3M._last_update_date def GetSource(self, config:SubscriptionDataConfig, date:datetime, isLiveMode:bool) -> SubscriptionDataSource: return SubscriptionDataSource("data.quantpedia.com/backtesting_data/interbank_rate/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv) def Reader(self, config:SubscriptionDataConfig, line:str, date:datetime, isLiveMode:bool) -> BaseData: data = InterestRate3M() data.Symbol = config.Symbol if not line[0].isdigit(): return None split = line.split(';') data.Time = datetime.strptime(split[0], "%Y-%m-%d") + relativedelta(months=2) data['value'] = float(split[1]) data.Value = float(split[1]) # store last update date if config.Symbol.Value not in InterestRate3M._last_update_date: InterestRate3M._last_update_date[config.Symbol.Value] = datetime(1,1,1).date() if data.Time.date() > InterestRate3M._last_update_date[config.Symbol.Value]: InterestRate3M._last_update_date[config.Symbol.Value] = data.Time.date() return data # Quandl "value" data class QuandlValue(PythonQuandl): def __init__(self): self.ValueColumnName = 'Value' # Custom fee model. class CustomFeeModel(FeeModel): def GetOrderFee(self, parameters): fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005 return OrderFee(CashAmount(fee, "USD"))
# https://quantpedia.com/strategies/dollar-carry-trade/ # # The investment universe consists of currencies from developed countries (the Euro area, Australia, Canada, Denmark, Japan, New Zealand, Norway, Sweden, # Switzerland, and the United Kingdom). The average forward discount (AFD) is calculated for this basket of currencies (each currency has an equal weight). # The average 3-month rate could be used instead of the AFD in the calculation. The AFD is then compared to the 3-month US Treasury rate. The investor # goes long on the US dollar and goes short on the basket of currencies if the 3-month US Treasury rate is higher than the AFD. The investor goes short # on the US dollar and long on the basket of currencies if the 3-month US Treasury rate is higher than the AFD. The portfolio is rebalanced monthly. import data_tools import numpy as np from AlgorithmImports import * from typing import Dict class DollarCarryTrade(QCAlgorithm): def Initialize(self): self.SetStartDate(2000, 1, 1) self.SetCash(100000) self.leverage:int = 2 # Source: https://fred.stlouisfed.org/series/IR3TIB01AUM156N self.symbols:Dict[str, str] = { "CME_AD1" : "IR3TIB01AUM156N", # Australian Dollar Futures, Continuous Contract #1 "CME_BP1" : "LIOR3MUKM", # British Pound Futures, Continuous Contract #1 "CME_CD1" : "IR3TIB01CAM156N", # Canadian Dollar Futures, Continuous Contract #1 "CME_EC1" : "IR3TIB01EZM156N", # Euro FX Futures, Continuous Contract #1 "CME_JY1" : "IR3TIB01JPM156N", # Japanese Yen Futures, Continuous Contract #1 "CME_MP1" : "IR3TIB01MXM156N", # Mexican Peso Futures, Continuous Contract #1 "CME_NE1" : "IR3TIB01NZM156N", # New Zealand Dollar Futures, Continuous Contract #1 "CME_SF1" : "IR3TIB01CHM156N" # Swiss Franc Futures, Continuous Contract #1 } for symbol in self.symbols: data = self.AddData(data_tools.QuantpediaFutures, symbol, Resolution.Daily) data.SetFeeModel(data_tools.CustomFeeModel()) data.SetLeverage(self.leverage) # Interbank rate data. cash_rate_symbol = self.symbols[symbol] self.AddData(data_tools.InterestRate3M, cash_rate_symbol, Resolution.Daily) self.treasury_rate:Symbol = self.AddData(data_tools.InterestRate3M, 'IR3TIB01USM156N', Resolution.Daily).Symbol def OnData(self, data:Slice) -> None: ir_last_update_date:Dict[str, datetime.date] = data_tools.InterestRate3M.get_last_update_date() qp_futures_last_update_date:Dict[str, datetime.date] = data_tools.QuantpediaFutures.get_last_update_date() fd:Dict[str, float] = {} for future_symbol, cash_rate_symbol in self.symbols.items(): if self.Securities[cash_rate_symbol].GetLastData() and ir_last_update_date[cash_rate_symbol] > self.Time.date(): if cash_rate_symbol in data and data[cash_rate_symbol]: if qp_futures_last_update_date[future_symbol] > self.Time.date(): cash_rate:float = data[cash_rate_symbol].Value # Update cash rate only once a month. fd[future_symbol] = cash_rate if len(fd) == 0: if self.Securities[self.treasury_rate].GetLastData() and ir_last_update_date[self.treasury_rate.Value] <= self.Time.date(): self.Liquidate() return afd:float = np.mean([x[1] for x in fd.items()]) treasuries_3m_rate:float = self.Securities[self.treasury_rate].Price count:int = len(self.symbols) if treasuries_3m_rate > afd: # Long on the US dollar and goes short on the basket of currencies. for symbol in self.symbols: if symbol in data and data[symbol]: self.SetHoldings(symbol, -1 / count) else: # Short on the US dollar and long on the basket of currencies. for symbol in self.symbols: if symbol in data and data[symbol]: self.SetHoldings(symbol, 1 / count)