腐败对外汇市场的影响
登录后收藏学术论文
Corruption, Carry Trades, and the Cross Section of Currency Returns
Corruption, carry trades, and the cross section of currency returns [点击查看论文]
- FIUniversity of Vaasa
- FIUniversity of Jyväskylä
- ?University of Jyväskyla
- ?University of Vaasa - Department of Accounting and Finance
策略概要
投资范围包括17种兑美元的流动性货币对。在每年年初,货币根据前一年的腐败感知指数(CPI)分为三分位数。低CPI表示高腐败,高CPI表示低腐败。投资组合做多CPI得分最高的五种货币,做空得分最低的五种货币。这个零成本投资组合每年重新平衡,旨在利用腐败认知与货币表现之间的关系。
II. 策略合理性
金融文献对外汇市场的关注是最近才出现的。外汇市场的第一个实证资产定价模型包括美元和利差风险因素。然而,腐败尚未被广泛认为是风险因素。一些研究表明,腐败遵循周期,并可能影响GDP增长。高腐败水平对国家及其货币都是有害的,可能通过引入额外的风险层、影响投资者行为和影响货币价值来影响金融市场。
回测表现
波动率8.14%
夏普比率0.74
胜率46%
完整 Python 代码
from AlgorithmImports import *
#endregion
class EffectCorruptionFX(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.symbols = {'CAD' : 'USDCAD',
'GBP' : 'USDGBP',
'MXN' : 'USDMXN',
'EUR' : 'USDEUR',
'NOK' : 'USDNOK',
'CHF' : 'USDCHF',
'SEK' : 'USDSEK',
'AUD' : 'USDAUD',
'NZD' : 'NZDUSD',
'JPY' : 'USDJPY',
'HKD' : 'USDHKD',
'SGD' : 'USDSGD',
'ZAR' : 'USDZAR',
'INR' : 'USDINR'
}
for symbol in self.symbols:
data = self.AddForex(self.symbols[symbol], Resolution.Daily, Market.FXCM)
self.cpi = self.AddData(CPIData, 'CPI', Resolution.Daily).Symbol
self.quantile = 3
first_key = [x for x in self.symbols.keys()][0]
self.Schedule.On(self.DateRules.MonthStart(self.symbols[first_key]), self.TimeRules.AfterMarketOpen(self.symbols[first_key]), self.Rebalance)
def Rebalance(self):
if self.Time.month != 1: return
cpi = {}
for symbol in self.symbols:
if self.Securities[self.cpi].GetLastData():
cpi[symbol] = self.Securities['CPI'].GetLastData()[symbol]
if len(cpi) < self.quantile:
self.Liquidate()
return
sorted_by_cpi = sorted(cpi.items(), key = lambda x: x[1], reverse = True)
quantile = int(len(sorted_by_cpi) / self.quantile)
long = [x[0] for x in sorted_by_cpi[:quantile]]
short = [x[0] for x in sorted_by_cpi[-quantile:]]
self.Liquidate()
long_count = len(long)
short_count = len(short)
for symbol in long:
if symbol == 'NZD':
self.SetHoldings(self.symbols[symbol], 1/long_count)
else:
self.SetHoldings(self.symbols[symbol], -1/long_count)
for symbol in short:
if symbol == 'NZD':
self.SetHoldings(self.symbols[symbol], -1/short_count)
else:
self.SetHoldings(self.symbols[symbol], 1/short_count)
# CPI data
# NOTE: IMPORTANT: Data order must be ascending (date-wise)
from dateutil.relativedelta import relativedelta
class CPIData(PythonData):
def GetSource(self, config, date, isLiveMode):
return SubscriptionDataSource("data.quantpedia.com/backtesting_data/economic/CPI.csv", SubscriptionTransportMedium.RemoteFile, FileFormat.Csv)
def Reader(self, config, line, date, isLiveMode):
data = CPIData()
data.Symbol = config.Symbol
if not line[0].isdigit(): return None
# Example File Format:
# year;CAD;GBP;MXN;EUR;NOK;CHF;SEK;AUD;NZD;JPY;HKD;SGD;ZAR;INR
# 2013;84;74;34;79;85;86;88;85;90;74;77;87;43;36
#
# YEARLY DATA
split = line.split(';')
data.Time = datetime.strptime(split[0], "%Y") + relativedelta(months=12) # NOTE: Preventing of look ahaead bias. Add 12 months so this year we see last year's data.
data.Value = split[1]
data['CAD'] = int(split[1])
data['GBP'] = int(split[2])
data['MXN'] = int(split[3])
data['EUR'] = int(split[4])
data['NOK'] = int(split[5])
data['CHF'] = int(split[6])
data['SEK'] = int(split[7])
data['AUD'] = int(split[8])
data['NZD'] = int(split[9])
data['JPY'] = int(split[10])
data['HKD'] = int(split[11])
data['SGD'] = int(split[12])
data['ZAR'] = int(split[13])
data['INR'] = int(split[14])
return data
# Custom fee model.
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))