Overall Statistics |
Total Orders
1389
Average Win
0.54%
Average Loss
-0.70%
Compounding Annual Return
-0.287%
Drawdown
45.900%
Expectancy
-0.028
Start Equity
100000
End Equity
93096.11
Net Profit
-6.904%
Sharpe Ratio
-0.331
Sortino Ratio
-0.376
Probabilistic Sharpe Ratio
0.000%
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
0.78
Alpha
-0.02
Beta
-0.053
Annual Standard Deviation
0.066
Annual Variance
0.004
Information Ratio
-0.36
Tracking Error
0.18
Treynor Ratio
0.416
Total Fees
$1046.26
Estimated Strategy Capacity
$0
Lowest Capacity Asset
CME_MP1.QuantpediaFutures 2S
Portfolio Turnover
2.20%
|
# 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. import data_tools from AlgorithmImports import * class CurrencyMomentumFactor(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2000, 1, 1) self.set_cash(100_000) period: int = 12 * 21 self.set_warm_up(period, Resolution.DAILY) tickers: List[str] = [ "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 ] self._securities: List[Security] = [] self._traded_count: int = 3 for symbol in tickers: data: Security = self.add_data(data_tools.QuantpediaFutures, symbol, Resolution.DAILY) data.set_fee_model(data_tools.CustomFeeModel()) data.set_leverage(5) data.roc: RateOfChange = self.ROC(symbol, period, Resolution.DAILY) self._securities.append(data) self._recent_month: int = -1 def on_data(self, slice: Slice) -> None: if self.is_warming_up: return # rebalance monthly if self.time.month == self._recent_month: return self._recent_month = self.time.month perf: Dict[Symbol, float] = { sec.symbol : sec.roc.current.value for sec in self._securities if sec.roc.is_ready and slice.contains_key(sec.symbol) and slice[sec.symbol] } long: List[Symbol] = [] short: List[Symbol] = [] if len(perf) >= self._traded_count * 2: sorted_by_performance: List[Symbol] = sorted(perf, key=perf.get, reverse=True) long = sorted_by_performance[:self._traded_count] short = sorted_by_performance[-self._traded_count:] # trade execution targets: List[PortfolioTarget] = [] for i, portfolio in enumerate([long, short]): for symbol in portfolio: targets.append(PortfolioTarget(symbol, ((-1) ** i) / len(portfolio))) self.set_holdings(targets, True)
#region imports from AlgorithmImports import * #endregion # Custom fee model class CustomFeeModel(FeeModel): def GetOrderFee(self, parameters): fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005 return OrderFee(CashAmount(fee, "USD")) # 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, is_live_mode: 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, is_live_mode: bool) -> BaseData: data = QuantpediaFutures() data.Symbol = config.Symbol if not line[0].isdigit(): return None split: List[str] = 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