Overall Statistics |
Total Orders
1809
Average Win
0.18%
Average Loss
-0.17%
Compounding Annual Return
2.538%
Drawdown
32.000%
Expectancy
0.408
Start Equity
100000
End Equity
186852.83
Net Profit
86.853%
Sharpe Ratio
-0.022
Sortino Ratio
-0.023
Probabilistic Sharpe Ratio
0.001%
Loss Rate
33%
Win Rate
67%
Profit-Loss Ratio
1.09
Alpha
-0.012
Beta
0.236
Annual Standard Deviation
0.077
Annual Variance
0.006
Information Ratio
-0.329
Tracking Error
0.139
Treynor Ratio
-0.007
Total Fees
$182.01
Estimated Strategy Capacity
$0
Lowest Capacity Asset
CME_MP1.QuantpediaFutures 2S
Portfolio Turnover
0.31%
|
# https://quantpedia.com/strategies/fx-carry-trade/ # # Create an investment universe consisting of several currencies (10-20). Go long three currencies with the highest central bank prime rates and # go short three currencies with the lowest central bank prime rates. The cash not used as the margin is invested in overnight rates. The strategy # is rebalanced monthly. # # QC implementation changes: # - Investment universe consisting of 8 currency futures. # - Most recent IR value is used for signal calculation. #region imports from AlgorithmImports import * import data_tools #endregion class ForexCarryTrade(QCAlgorithm): def Initialize(self): self.SetStartDate(2000, 1, 1) self.SetCash(100000) # Source: https://fred.stlouisfed.org/series/IR3TIB01AUM156N self.tickers: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 } self.traded_count:int = 3 self.leverage:int = 3 for ticker, rate_symbol in self.tickers.items(): self.AddData(data_tools.InterestRate3M, rate_symbol, Resolution.Daily) data = self.AddData(data_tools.QuantpediaFutures, ticker, Resolution.Daily) data.SetFeeModel(data_tools.CustomFeeModel()) data.SetLeverage(self.leverage) self.recent_month = -1 self.Settings.MinimumOrderMarginPortfolioPercentage = 0. def OnData(self, data: Slice) -> None: rebalance_flag: bool = False rate: Dict[Symbol, float] = {} ir_last_update_date: Dict[str, datetime.date] = data_tools.InterestRate3M.get_last_update_date() for ticker, int_rate in self.tickers.items(): # futures data is present in the algorithm if ticker in data and data[ticker]: if self.recent_month != self.Time.month: rebalance_flag = True self.recent_month = self.Time.month if rebalance_flag: # IR data is still comming in if self.Securities[int_rate].GetLastData() and ir_last_update_date[int_rate] > self.Time.date(): # take last IR value rate[self.Symbol(ticker)] = self.Securities[int_rate].Price if rebalance_flag: targets:List[PortfolioTarget] = [] if len(rate) >= self.traded_count: # interbank rate sorting sorted_by_rate:List[Symbol] = sorted(rate, key = rate.get, reverse = True) long:List[Symbol] = sorted_by_rate[:self.traded_count] short:List[Symbol] = sorted_by_rate[-self.traded_count:] # order execution for i, portfolio in enumerate([long, short]): for symbol in portfolio: if symbol in data and data[symbol]: targets.append(PortfolioTarget(symbol, ((-1) ** i) / len(portfolio))) self.SetHoldings(targets, True)
#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: SubscriptionDataConfig, date: datetime, isLiveMode: bool) -> SubscriptionDataSource: return SubscriptionDataSource("data.quantpedia.com/backtesting_data/futures/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv) def Reader(self, config: SubscriptionDataConfig, line: str, date: datetime, isLiveMode: bool) -> BaseData: 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 # Custom fee model. class CustomFeeModel(): def GetOrderFee(self, parameters): fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005 return OrderFee(CashAmount(fee, "USD")) 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