平均回帰戦略

平均回帰戦略を作成してみる。

トレンドは敵

「トレンドは友」と言われるが、平均回帰戦略ではトレンドは敵である。単に売られ過ぎを買い、買われ過ぎを売るというだけでは、なかなか勝てる戦略にはならない。トレンドが発生すると、それまでに稼いだ利益はごっそり持って行かれてしまう。

トレンドを回避する方法としては

  1. トレンド系指標でトレンドの方向を確認して、それに逆らわない形でエントリーする
  2. より長い計算期間でトレンドの方向を確認して、それに逆らわない形でエントリーする
  3. トレンドの変換を確認してからエントリーする

といったことがテクニカル分析ではよく言われる。

ただ、私の経験上、少なくとも短期トレードでは1、2は役に立たず、3は利益の幅を縮小して結局勝てない、という印象が強い。

トレンドは回避するのではなくてやり過ごす

私はトレンドを回避するよりもやり過ごすのが有効だと考えている。そもそも、トレンドは発生の初期段階で認識することは難しい。トレンドが発生したことを認識できたときには、もはやトレンドに乗るには遅すぎ、といって反転するかいなかは分からないという微妙なタイミングである。

だが、トレンドは決して永続しない。トレンドの発生を確認し、しばらく待てばトレンドはいずれ収束する。少なくとも、それまでに稼いだ利益をごっそり持って行ってしまうほどの勢いは残されていないのである。

平均回帰戦略の売買ルール

以上の考えに基づき、以下のような売買ルールを考えてみる。

買いエントリー

  1. zスコアがマイナスのエントリー閾値以下、かつ、
  2. トレンド期間がマイナスのフィルター閾値以下。

売りエントリー

  1. zスコアがプラスのエントリー閾値以上、かつ、
  2. トレンド期間がプラスのフィルター閾値以上。

買いエグジット

  • zスコアが0以上。

売りエグジット

  • zスコアが0以下。

備考

  1. この記事のzスコアとは終値を移動平均で減じ、それを移動標準偏差で除したものである。。
  2. この記事のトレンド期間とは価格が連続して移動平均の上に位置する期間(符号はプラス)、または下に位置する期間(符号はマイナス)のことである。

サンプルプログラム

上述の売買ルールに基づいて作成したサンプルプログラムは以下の通りである。

# coding: utf-8

import forex_system as fs

LOTS = 0.1

# パラメータの設定
MINUTE = 60
ENTRY_THRESHOLD = 0.5
FILTER_THRESHOLD = 2.0
PARAMETER = [MINUTE, ENTRY_THRESHOLD, FILTER_THRESHOLD]

# 最適化の設定
START_MINUTE = 60
END_MINUTE = 300
STEP_MINUTE = 60
START_ENTRY_THRESHOLD = 0.5
END_ENTRY_THRESHOLD = 2.5
STEP_ENTRY_THRESHOLD = 0.5
START_FILTER_THRESHOLD = 0.5
END_FILTER_THRESHOLD = 2.5
STEP_FILTER_THRESHOLD = 0.5
RRANGES = (
    slice(START_MINUTE, END_MINUTE, STEP_MINUTE),
    slice(START_ENTRY_THRESHOLD, END_ENTRY_THRESHOLD, STEP_ENTRY_THRESHOLD),
    slice(START_FILTER_THRESHOLD, END_FILTER_THRESHOLD, STEP_FILTER_THRESHOLD),
)

def strategy(parameter, symbol, timeframe):
    '''戦略を記述する。
    Args:
        parameter: パラメーター。
        symbol: 通貨ペア。
        timeframe: 期間。
    Returns:
        シグナル。
    '''
    # パラメーターを格納する。
    minute = int(parameter[0])
    entry_threshold = float(parameter[1])
    filter_threshold = float(parameter[2])
    # 戦略を記述する。
    period = fs.convert_minute2period(minute, timeframe)
    slope = 0.608286152451
    intercept = -1.1255204743
    divisor = slope * period + intercept
    zscore1 = fs.i_zscore(symbol, timeframe, period, 'MODE_SMA', 1)
    bandwalk1 = (fs.i_bandwalk(symbol, timeframe, period, 'MODE_SMA', 1)
        / divisor)
    buy_entry = (
        (zscore1 <= -entry_threshold) &
        (bandwalk1 <= -filter_threshold)
        )
    buy_exit = zscore1 >= 0.0
    sell_entry = (
        (zscore1 >= entry_threshold) &
        (bandwalk1 >= filter_threshold)
        )
    sell_exit = zscore1 <= 0.0

    return (symbol, timeframe, buy_entry, buy_exit, sell_entry, sell_exit,
            LOTS, 0, 0)


これをSpyderの「エディタ」にコピー・アンド・ペーストし、ファイル名を「mean_reversion.py」として「~/py」フォルダーに保存する。

売買ルールの検証

では、このサンプルプログラムを使って売買ルールの検証を行ってみる。

  • EA: mean_reversion
  • 通貨ペア: USDJPY
  • スプレッド: 0.4pips
  • 足の種類: 5分足
  • 開始日: 2013年1月1日
  • 終了日: 2016年12月31日
  • 最適化: ウォークフォワードテスト

という設定である。

In [1]:
%run -t ~/py/backtest.py --ea1 mean_reversion --symbol1 USDJPY --spread1 0.4 --timeframe 5 --start 2013.01.01 --end 2016.12.31 --optimization 2


    start_test    end_test trades    apr sharpe    kelly drawdowns durations   parameter1 weights
0   2013.12.27  2014.01.25    117 -0.001 -0.004   -0.096     0.012        18   [1.5, 0.5]   [1.0]
1   2014.01.26  2014.02.24    123   0.35  9.565  264.891     0.006         4   [1.5, 0.5]   [1.0]
2   2014.02.25  2014.03.26    111  0.196  6.653  227.406     0.005         7   [1.5, 0.5]   [1.0]
3   2014.03.27  2014.04.25    124  0.095  3.348  117.649     0.005         8   [1.5, 0.5]   [1.0]
4   2014.04.26  2014.05.25    103  0.011  0.528   24.182     0.005         7   [1.5, 0.5]   [1.0]
5   2014.05.26  2014.06.24    114  0.101  6.127   373.18     0.002         2   [1.5, 0.5]   [1.0]
6   2014.06.25  2014.07.24    113  0.007  0.465   30.847     0.005        17   [1.5, 0.5]   [1.0]
7   2014.07.25  2014.08.23    112   0.04  2.006   99.139     0.003         7   [1.5, 0.5]   [1.0]
8   2014.08.24  2014.09.22    117 -0.034 -1.099   -36.17     0.013        19   [1.5, 0.5]   [1.0]
9   2014.09.23  2014.10.22    138  0.386  7.796  159.464     0.015         2   [1.5, 0.5]   [1.0]
10  2014.10.23  2014.11.21    123  0.167  3.612   78.105     0.014         8   [1.5, 0.5]   [1.0]
11  2014.11.22  2014.12.21    119   0.37  6.122  102.382     0.015         4   [1.5, 0.5]   [1.0]
12  2014.12.22  2015.01.20    121  0.063   1.17   21.379      0.01        13   [1.5, 0.5]   [1.0]
13  2015.01.21  2015.02.19    116  0.342  9.023  241.041     0.005         3   [1.5, 0.5]   [1.0]
14  2015.02.20  2015.03.21    103    0.1  2.466   60.636     0.011         3   [1.5, 0.5]   [1.0]
15  2015.03.22  2015.04.20    128 -0.014 -0.401  -12.087     0.012        17   [1.5, 0.5]   [1.0]
16  2015.04.21  2015.05.20    123  0.083  2.707    88.46     0.006         5   [1.5, 0.5]   [1.0]
17  2015.05.21  2015.06.19     61  0.096  4.099  175.404     0.004         5  [1.5, 0.75]   [1.0]
18  2015.06.20  2015.07.19     61  0.107  4.547  193.778     0.005         5  [1.5, 0.75]   [1.0]
19  2015.07.20  2015.08.18     26 -0.013 -0.811  -50.338     0.006        10   [1.5, 1.0]   [1.0]
20  2015.08.19  2015.09.17     25  0.018  0.598   19.913     0.006        11   [1.5, 1.0]   [1.0]
21  2015.09.18  2015.10.17     47 -0.041   -1.8  -78.528     0.007        12  [1.5, 0.75]   [1.0]
22  2015.10.18  2015.11.16     27  0.031  1.857  110.617     0.004         5   [1.5, 1.0]   [1.0]
23  2015.11.17  2015.12.16     36  0.018  1.124     69.4     0.005         6   [1.5, 1.0]   [1.0]
24  2015.12.17  2016.01.15     62  0.256  9.889  386.208     0.004         4  [1.5, 0.75]   [1.0]
25  2016.01.16  2016.02.14     55  0.207  4.995  121.295     0.007         5  [1.5, 0.75]   [1.0]
26  2016.02.15  2016.03.15     68  0.104  2.922   81.683     0.008         6  [1.5, 0.75]   [1.0]
27  2016.03.16  2016.04.14     28  0.048  2.316  111.077     0.005        17   [1.5, 1.0]   [1.0]
28  2016.04.15  2016.05.14     56  0.051  1.484   43.073     0.009        15  [1.5, 0.75]   [1.0]
29  2016.05.15  2016.06.13     64  0.092  2.781   84.173     0.005        10  [1.5, 0.75]   [1.0]
30  2016.06.14  2016.07.13     51 -0.064 -1.383  -30.152     0.013        11  [1.5, 0.75]   [1.0]
31  2016.07.14  2016.08.12    120 -0.108 -1.604  -24.186     0.021        14   [1.5, 0.5]   [1.0]
32  2016.08.13  2016.09.11    106  0.108  2.632   64.107     0.013        10   [1.5, 0.5]   [1.0]
33  2016.09.12  2016.10.11    111  0.258  5.663  125.334     0.007         7   [1.5, 0.5]   [1.0]
34  2016.10.12  2016.11.10    112 -0.264 -3.963  -59.334      0.03        12   [1.5, 0.5]   [1.0]
35  2016.11.11  2016.12.10    122   0.24   4.34   78.812     0.012         5   [1.5, 0.5]   [1.0]
36  2013.12.27  2016.12.10   3243  0.108  2.518   67.426      0.03        78



IPython CPU timings (estimated):
  User   :     412.88 s.
  System :      16.30 s.
Wall time:     364.52 s.


年率は10.8%、シャープレシオは2.52となっており、まずまずである。

(2017/03/18更新)

コメント

非公開コメント