政府の市場介入によるバイアス (2017/04/17)

政府の市場介入によるバイアスによってパフォーマンスがどうなるか、そして、バイアスを除いたあとのパフォーマンスがどうなるかを見てみる。

スイスフランショック

政府の市場介入は価格形成に歪みを与える。その歪みを利用して利益を上げることも可能ではある。だが、恐ろしいのは政府が方針を変更したときである。2015年1月15日に起きたスイスフランショックは記憶に新しい。

スイスフラン高を嫌ったスイス中銀は2011年9月、ユーロスイスの下限を1.2スイスフランに設定して無制限介入を開始した。ユーロスイスが1.2スイスフランを割ることはないとスイス中銀が保証してくれたわけだ。これをバックにして買えば低リスクで利益を上げられると考えたトレーダーも少なくなかっただろう。

かく言う私もスイス中銀の介入をバックにして下がったら買う逆張り戦略をブログで記事にした。ただ、スイス中銀が無制限介入を行ったときにユーロスイスが暴騰したことを挙げて、スイス中銀が方針を変換したら逆のことが起きると警告した。また、1.2スイスフランを割ったら損切りすべきだとも書いた。だが、私の認識は甘すぎた。

スイス中銀が下限を撤廃したことが伝わると、スプレッドが大きく広がり、そしてレート配信が止まった。運よく損切りできても想定以上の損失を受けただろうし、損切りできず、ロスカットすらできずに全資金を失い、さらにはFX会社に対して負債すら抱えてしまったトレーダーも少なくなかった。FX会社が負債を回収できずに倒産するというケースもあった。幸い、私は記事にしただけで実際には運用しなかった。だが、いい加減な記事を書いてはいけないと痛感した。

一時的には勝てるが…

政府の介入によって歪められた市場のデータを使ってバックテストしても、その寿命はその介入が継続している間だけに限られる。そして、介入は何のアナウンスもなく突然撤廃され、後は阿鼻叫喚の地獄がやってくるのである。

例として直近安値をバックにしてユーロスイスを買う戦略を考えてみる。具体的には

  • 終値が直近安値*(1+エントリー閾値/100)以下になったら買いエントリー、
  • 終値が直近安値*(1+(エントリー閾値+エグジット閾値)/100)以上になったら買いエグジット、

という売買ルールである。

では、上記の売買ルールに基づき、2012年1月1日から2015年1月1日までの期間でバックテストしてみる。

以下のコードを「swiss_franc_shock.py」ファイルとして「~/py」フォルダーに保存する。

# coding: utf-8

import forex_system as fs

# パラメータの設定
PERIOD = 1500
ENTRY_THRESHOLD = 0.002
PROFIT_THRESHOLD = 0.08
PARAMETER = [PERIOD, ENTRY_THRESHOLD, PROFIT_THRESHOLD]

# 最適化の設定
START_PERIOD = 250
END_PERIOD = 2500
STEP_PERIOD = 250
START_ENTRY_THRESHOLD = 0.001
END_ENTRY_THRESHOLD = 0.01
STEP_ENTRY_THRESHOLD = 0.001
START_PROFIT_THRESHOLD = 0.01
END_PROFIT_THRESHOLD = 0.1
STEP_PROFIT_THRESHOLD = 0.01
RRANGES = (
    slice(START_PERIOD, END_PERIOD, STEP_PERIOD),
    slice(START_ENTRY_THRESHOLD, END_ENTRY_THRESHOLD, STEP_ENTRY_THRESHOLD),
    slice(START_PROFIT_THRESHOLD, END_PROFIT_THRESHOLD, STEP_PROFIT_THRESHOLD),
)

build_model = None

def strategy(parameter, symbol, timeframe):
    '''戦略を記述する。
    Args:
        parameter: パラメーター。
        symbol: 通貨ペア。
        timeframe: 期間。
    Returns:
        買いエントリー、買いエグジット、売りエントリー、売りエグジット、ユニット数。
    '''
    # パラメータを格納する。
    period = int(parameter[0])
    entry_threshold = float(parameter[1])
    profit_threshold = float(parameter[2])
    # 戦略を記述する。
    close1 = fs.i_close(symbol, timeframe, 1)
    hl_band1 = fs.i_hl_band(symbol, timeframe, period, 1)
    buy_entry = close1 <= hl_band1['low'] * (1 + entry_threshold / 100)
    buy_exit = (close1 >= hl_band1['low'] *
                (1 + (entry_threshold + profit_threshold) / 100))
    sell_entry = close1 != close1  # 売りはやらないので無意味な条件を与える。
    sell_exit = close1 != close1  # 同上。
    index = close1.index
    units = fs.get_units(1.0, index)
    return buy_entry, buy_exit, sell_entry, sell_exit, units

if __name__ == '__main__':
    fs.platform()

以下のコマンドを実行してバックテストする。

%run -t ~/py/swiss_franc_shock.py --mode backtest --symbol EURCHF --timeframe 5 --spread 2.0 --start 2012.01.01 --end 2015.01.01


       start         end trades   apr sharpe    kelly drawdowns durations              parameter
  2012.01.01  2014.12.31    115  0.01  1.661  269.309     0.005        55  [1500.0, 0.002, 0.08]

シャープレシオはそれほど高くはないが、資産曲線は比較的きれいな右肩上がりとなっている。

地獄は突然やってくる

2015年でも同様のパフォーマンスを期待したいが、残念ながらスイス中銀は1月15日、突如としてスイスフランの下限を撤廃する。では、すでに最適化されたパラメータを使い、期間を2016年1月1日まで延長したデータでどうなるかを見てみる。

以下のコマンドを実行してバックテストする。

%run -t ~/py/swiss_franc_shock.py --mode backtest --symbol EURCHF --timeframe 5 --spread 2.0 --start 2012.01.01 --end 2016.01.01


      start         end trades    apr sharpe  kelly drawdowns durations              parameter
  2012.01.01  2015.12.31    155 -0.032  -0.41 -5.408     0.187       258  [1500.0, 0.002, 0.08]

一体何が起きたのか、という感じである。3年もかけてコツコツと積み上げた利益など一瞬で消えてしまい、約10%以上の負けとなっている。

しかも、これはレバレッジが1倍ならの話である。もしレバレッジが10倍だったら、全資金を失うばかりか、負債まで抱えることとなっていただろう。実際にはスプレッドは広がるし、レート配信は停止するしで、バックテストよりもっとひどいことになっていたかもしれない。

トレードで利益を上げるには単に市場の歪みを捉えるだけではなく、それが継続性のあるものでなければならない。政府によって一時的に作られた歪みによって利益を得ようとすることは後々とんでもないしっぺ返しを受けることになる。

コメント

非公開コメント