
“该策略使用利率差动量信号交易11个主要货币对,并在伦敦与纽约市场收盘时进行每日两次再平衡,以利用基于利率驱动的市场低效性。”
资产类别:差价合约(CFDs)、远期合约(forwards)、期货、掉期 | 区域:全球 | 频率:日内 | 市场:外汇市场 | 关键词:利率、动量、汇率
I. 策略概述
交易范围:
涉及11个主要货币对,包括:AUD、CAD、CHF、DKK、EUR、GBP、JPY、NOK、NZD、SEK、USD。
信号生成:
- 利率差动量信号(+1/-1):
比较货币对的利率差与其15天简单移动平均值。 - 再平衡:
通过动态调整仓位,该策略捕捉由利率差异引发的外汇市场动量。
II. 策略合理性
- 利率对货币的影响:
- 动量效应的来源:
该策略通过系统性买入利率预期上升的货币并卖出预期下降的货币,利用这些市场低效性获利
III. 论文来源
ANANTA: A Systematic Quantitative FX Trading Strategy [点击浏览原文]
- Nicolas Georges, 独立研究员
<摘要>
本文是系列研究的第一篇,旨在详细研究ANANTA策略,这是一种使用固定收益信号的短期系统化外汇模型。本部分重点描述策略的背景及基本实施方法,包括交易假设、信号构建及结果分析。


IV. 回测表现
| 年化收益率 | 9.01% |
| 波动率 | 5.54% |
| Beta | -0.075 |
| 夏普比率 | 1.63 |
| 索提诺比率 | N/A |
| 最大回撤 | N/A |
| 胜率 | 46% |
V. 完整python代码
import data_tools
from AlgorithmImports import *
import numpy as np
class InterestRatesMomentumPredictsFXRates(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
# Country symbol and currency future symbol.
self.symbols = {
"USD" : "not_traded", # US Dollar index Futures, Continuous Contract #1
"EUR" : "CME_EC1", # Euro FX Futures, Continuous Contract #1
"GBP" : "CME_BP1", # British Pound Futures, Continuous Contract #1
"CHF" : "CME_SF1", # Swiss Franc Futures, Continuous Contract #1
"JPY" : "CME_JY1", # Japanese Yen Futures, Continuous Contract #1
}
# Interest rate data.
self.interest_rate = self.AddData(data_tools.InterestRate, 'InterestRate', Resolution.Daily).Symbol
self.period = 15
self.yield_difference = {}
countries = [x[0] for x in self.symbols.items()]
for i, country1 in enumerate(countries):
for j, country2 in enumerate(countries):
if i <= j: continue
self.yield_difference[country1 + country2] = RollingWindow[float](self.period)
for country, currency_future in self.symbols.items():
# Currency futures data.
data = self.AddData(data_tools.QuantpediaFutures, currency_future, Resolution.Daily)
data.SetLeverage(10)
data.SetFeeModel(data_tools.CustomFeeModel())
def OnData(self, data):
if not self.Securities.ContainsKey(self.interest_rate): return
interest_rate_date = self.Securities[self.interest_rate].GetLastData()
if not interest_rate_date: return
# make sure interest data is still comming in
if (self.Time.date() - interest_rate_date.Time.date()).days >= 5:
self.Liquidate()
return
countries = [x[0] for x in self.symbols.items()]
signal = {}
for i, country1 in enumerate(countries):
sub_signal = {}
for j, country2 in enumerate(countries):
if i <= j: continue
index = country1 + country2
yield1 = interest_rate_date[country1]
yield2 = interest_rate_date[country2]
diff = yield1 - yield2
self.yield_difference[index].Add(diff)
if self.yield_difference[index].IsReady:
avg_diff = np.mean([x for x in self.yield_difference[index]])
sub_signal[index] = (diff - avg_diff) / abs(avg_diff)
if len(sub_signal) > 0:
abs_percentile = np.percentile([abs(x[1]) for x in sub_signal.items()], 50)
for signal_index, sig in sub_signal.items():
iter_country1 = signal_index[:3]
iter_country2 = signal_index[-3:]
if abs(sig) > abs_percentile:
if iter_country1 != 'USD':
iter_future1 = self.symbols[iter_country1]
if iter_future1 not in signal:
signal[iter_future1] = 0
signal[iter_future1] += np.sign(sig)
if iter_country2 != 'USD':
iter_future2 = self.symbols[iter_country2]
if iter_future2 not in signal:
signal[iter_future2] = 0
signal[iter_future2] -= np.sign(sig)
if len(signal) != 0:
futures_invested = [x.Key.Value for x in self.Portfolio if x.Value.Invested]
for currency_future in futures_invested:
if currency_future not in signal:
self.Liquidate(currency_future)
foo = 3
for currency_future, country_signal in signal.items():
self.SetHoldings(currency_future, country_signal)