基本的な平均回帰戦略

トレードルール

基本的な平均回帰戦略のトレードルールは以下の通りである。

買いエントリー

①zスコアがマイナスのエントリー閾値以下、かつ

②バンドウォークがマイナスのフィルター閾値以下。

売りエントリー

①zスコアがプラスのエントリー閾値以上、かつ

②バンドウォークがプラスのフィルター閾値以上。

買いエグジット

○zスコアが0以上。

売りエグジット

○zスコアが0以下。

備考

①この記事のzスコアとは終値を移動平均で減じ、それを移動標準偏差で除したものである。。

②この記事のバンドウォークとは安値が連続して移動平均を上回っている期間(符号はプラス)、または高値が連続して移動平均を下回っている期間(符号はマイナス)を標準化したものである。

③標準化に使用した傾き、切片はシミュレーションによって得たものなので厳密なものではない。

④四本値は対数変換したものを用いている。

サンプルプログラム

①以下のプログラムをSpyderの「エディタ」にコピー&ペーストし、ファイル名を「basic_mean_reversion.py」として「~/py」フォルダーに保存する。

# coding: utf-8

import forex_system as fs
# パラメータの設定
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
    signal = fs.calc_signal(buy_entry, buy_exit, sell_entry, sell_exit)

    return signal

②以下のコマンドをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを押す。

%run -t ~/py/backtest.py --ea1 basic_mean_reversion --symbol1 USDJPY --spread1 4 --timeframe 5 --start 2013.01.01 --end 2016.12.31 --optimization 2
(2017/01/30更新)

順張り逆張り、利食い損切り、ナンピンについて

順張りは正しいが、逆張りは間違っている、といった主張を時々見かける。また、遅く利食い、早く損切りするのは正しいが、早く利食い、遅く損切りするのは間違っている、といった主張も時々見かける。さらにナンピンは間違っている、といった主張も時々見かける。果たしてそうなのか。

それらについて私なりの考えをまとめてみた。あくまでも私の見方であって、これが正しいと主張するつもりはない。

順張りとは

順張りとは上がれば買い、下がれば売ることである。

逆張りとは

逆張りとは下がれば買い、上がれば売ることである。

どのようなとき、順張りは正当化されるか

上がればさらに上がる、下がればさらに下がるとトレーダーが判断しているとき、つまり順張り有利と判断しているとき、順張りは正当化される。その判断が正しいかいなかは問わない。

トレーダーが順張り有利と判断しているとき、上がれば買い、下がれば売るのは例え損失という結果をもたらしたとしても合理的な行動である。

トレーダーが順張り有利と判断しているとき、上がれば売り、下がれば買うのは例え利益という結果をもたらしたとしても合理的な行動ではない。

どのようなとき、逆張りは正当化されるか

下がれば反転して上がる、上がれば反転して下がるとトレーダーが判断しているとき、つまり逆張り有利と判断しているとき、逆張りは正当化される。その判断が正しいかいなかは問わない。

トレーダーが逆張り有利と判断しているとき、下がれば買い、上がれば売るのは例え損失という結果をもたらしたとしても合理的な行動である。

トレーダーが逆張り有利と判断しているとき、下がれば売り、上がれば買うのは例え利益という結果をもたらしたとしても合理的な行動ではない。

利食いとは

利食いとは損益が利益となっている状態でエグジットすることである。

損切りとは

損切りとは損益が損失となっている状態でエグジットすることである。

どのようなとき、利食いは正当化されるか

順張りで買って上がったとき、トレーダーはさらに上がると予想すべきだから、ここで利食うのは合理的な行動ではなく、正当化されない。

順張りで売って下がったとき、トレーダーはさらに下がると予想すべきだから、ここで利食うのは合理的な行動ではなく、正当化されない。

逆張りで買って上がったとき、トレーダーは反転して下がると予想すべきだから、ここで利食うのは合理的な行動であり、正当化される。

逆張りで売って下がったとき、トレーダーは反転して上がると予想すべきだから、ここで利食うのは合理的な行動であり、正当化される。

どのようなとき、損切りは正当化されるか

順張りで買って下がったとき、トレーダーはさらに下がると予想すべきだから、ここで損切るのは合理的な行動であり、正当化される。

順張りで売って上がったとき、トレーダーはさらに上がると予想すべきだから、ここで損切るのは合理的な行動であり、正当化される。

逆張りで買って下がったとき、トレーダーは反転して上がると予想すべきだから、ここで損切るのは合理的な行動ではなく、正当化されない。

逆張りで売って上がったとき、トレーダーは反転して下がると予想すべきだから、ここで損切るのは合理的な行動ではなく、正当化されない。

どのようなとき、順張りの利食いは正当化されるか

順張りで買って上がり、かつ順張り有利から逆張り有利へのレジームスイッチが発生したと判断したとき、トレーダーは反転して下がると予想すべきだから、ここで利食うのは合理的な行動であり、正当化される。

順張りで売って下がり、かつ順張り有利から逆張り有利へのレジームスイッチが発生したと判断したとき、トレーダーは反転して上がると予想すべきだから、ここで利食うのは合理的な行動であり、正当化される。

どのようなとき、逆張りの損切りは正当化されるか

逆張りで買って下がり、かつ逆張り有利から順張り有利へのレジームスイッチが発生したと判断したとき、トレーダーはさらに下がると予想すべきだから、ここで損切るのは合理的な行動であり、正当化される。

逆張りで売って上がり、かつ逆張り有利から順張り有利へのレジームスイッチが発生したと判断したとき、トレーダーはさらに上がると予想すべきだから、ここで損切るのは合理的な行動であり、正当化される。

ナンピンとは

ナンピンとは買った後に下がったら更に買い増し、売った後に上がったら更に売り増すことである。

どのようなとき、ナンピンは正当化されるか

トレーダーが逆張り有利と判断しているとき、ナンピンは正当化される。その判断が正しいかいなかは問わない。

トレーダーが順張り有利と判断しているとき、ナンピンは正当化されない。

買ったら下がってしまい、売ったら上がってしまって含み損を抱え、逆張り有利という判断もなく、ただ反転することを祈っているだけのとき、ナンピンは正当化されない。

(2016/11/29更新)

期待利益がマイナスの戦略は捨てるべきか

本題に入る前に基本的なことを確認しておく。

期待利益とシャープレシオの関係

ここに1年当たり100トレード、1トレード当たりの期待利益が0.1%、リスクが1.0%の戦略があるとする。単純化して考えると、1年当たりの期待利益は0.1% * 100 = 10.0%、リスクは√Tルールに基づけば1.0% * sqrt(100) = 10.0%となる。したがって、シャープレシオは10.0 / 10.0 = 1.0となる。これを戦略Aとする。

一方、1年当たり100トレード、1トレード当たりの期待利益が0.2%、リスクが4.0%の戦略があるとする。同様に考えて、1年当たりの期待利益は0.2% * 100 = 20.0%、リスクは4.0% * sqrt(100) = 40.0%となる。したがって、シャープレシオは20.0 / 40.0 = 0.5となる。これを戦略Bとする。

戦略Bの期待利益は戦略Aの2倍である。では戦略Bのほうが優れているかといえばそういうわけではない。1年後の利益はリスクも考慮すると1年当たりの期待利益 ± 1年当たりのリスクであるから、戦略Aは10% ± 10%、つまり0%〜20%となる。一方、戦略Bは20% ± 40%、つまり-20%〜60%となる。

都合よく考えると、戦略Aは20%、戦略Bは60%の利益だから戦略Bのほうがいいということになるが、果たしてそうか。逆に都合悪く考えると、戦略Aは0%、戦略Bは-20%となり、戦略Aは単に利益が出ないだけだが、戦略Bは-20%の損失である。だが、リスクを等しくしないと比較できないのである。

戦略Aで戦略Bと同じ4.0%のリスクを覚悟できるなら、投資額を4倍にすればいい(資金があればだが)。すると、期待利益も4倍になり、1年当たりの期待利益は0.4% * 100 = 40%、リスクは4.0% *sqrt(100) = 40%となる。1年後のリスクは40% ± 40%、つまり0〜80%となり、都合よく考えても、都合悪く考えても戦略Aは戦略Bより優れている。

つまり、期待利益が大きいかどうかが大事なのではなく、期待利益とリスクの比、つまりシャープレシオが大きいかどうかが大事なのである。期待利益は小さいがシャープレシオが大きい戦略は、期待利益は大きいがシャープレシオが小さい戦略と同じリスクを負うことで後者より大きい利益を生むことができるのである(机上の計算では)。

期待利益がマイナスの戦略でも役に立つ場合がある

さて、期待利益とシャープレシオの関係を確認したところで本題に入る。

ここに勝つ場合は+1、負ける場合は-1で一定で、1年当たり12回勝ち、8回負けるという戦略Aがあるとする。計算すると、期待利益は0.2、リスクは0.98、シャープレシオは0.91となる。

一方、勝つ場合は+0.5、負ける場合は-0.5で一定で、戦略Aが勝てば必ず負け、負ければ必ず勝つという戦略Bがあるとする。計算すると、期待利益は-0.1、リスクは0.49、シャープレシオは-0.91となる。

戦略Aと戦略Bの相関係数を求めると-1.0となる。勝敗が正反対なのであるから当然である。

ここで戦略Aと戦略Bを合わせた戦略Cを考えてみる。計算すると、期待利益は0.1、リスクは0.49、シャープレシオは0.91となる。戦略Aと比べると、期待利益は半減したが、リスクも半減したのでシャープレシオは変わらない。したがって、戦略Cはシャープレシオにおいて戦略Aと同等である。戦略Cが投資額を倍にして戦略Aと同じリスクを負うなら、期待利益も同じになる(資金の使い方としては非効率だが)。

ところで、戦略Bの負けを1つだけ勝ちだったことにしてみる。再計算すると、期待利益は-0.05、リスクは0.49、シャープレシオは-0.45となる。元の戦略と比べると、期待利益は半減したが、リスクはそのままなので、シャープレシオも半減する。ただし、期待利益はマイナスなので、これは改善である。

戦略Aと新しい戦略Bの相関係数を求めると-0.91となる。勝敗が完全には反対でないので、これも当然である。

そして、戦略Aにこの新しい戦略Bを合わせて新しい戦略Cを考えてみる。再計算すると、期待利益は0.15、リスクは0.57、シャープレシオは1.17となる。戦略Aと比べると、期待利益は減少しているが、リスクはそれ以上に減少しているので、シャープレシオは大きくなっている。したがって、新しい戦略Cはシャープレシオにおいて戦略Aより優れている。

つまり、新しい戦略Bを加えることによって戦略Aは改善されたのである。だが、新しい戦略Bの期待利益は-0.05であり、マイナスである。にもかかわらず、戦略Aを改善したのだ。

したがって、期待利益がマイナスの戦略でも役に立つ場合があると言える。ならば、いきなり捨てたりはせずに使い道がないか考えてみてもいいのではないだろうか。

a =  [ 1  1  1  1  1  1  1  1  1  1  1  1 -1 -1 -1 -1 -1 -1 -1 -1]
mean_a =  0.2
std_a =  0.979795897113
sharpe_a =  0.912870929175
b =  [-0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5  0.5  0.5  0.5
  0.5  0.5  0.5  0.5  0.5]
mean_b =  -0.1
std_b =  0.489897948557
sharpe_b =  -0.912870929175
cor_ab =  -1.0
c =  [ 0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5 -0.5 -0.5 -0.5
 -0.5 -0.5 -0.5 -0.5 -0.5]
mean_c =  0.1
std_c =  0.489897948557
sharpe_c =  0.912870929175
b2 =  [ 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5  0.5  0.5  0.5
  0.5  0.5  0.5  0.5  0.5]
mean_b2 =  -0.05
std_b2 =  0.497493718553
sharpe_b2 =  -0.449466574975
cor_ab2 =  -0.902670933848
c2 =  [ 1.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5  0.5 -0.5 -0.5 -0.5
 -0.5 -0.5 -0.5 -0.5 -0.5]
mean_c2 =  0.15
std_c2 =  0.572276157113
sharpe_c2 =  1.17219699775

サンプルプログラム

○以下のコマンドをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを2回押す。

# coding: utf-8

import numpy as np

a = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              1, 1, -1, -1, -1, -1, -1, -1, -1, -1])
print('a = ', a)
mean_a = np.mean(a)
print('mean_a = ', mean_a)
std_a = np.std(a)
print('std_a = ', std_a)
sharpe_a = mean_a / std_a * np.sqrt(20)
print('sharpe_a = ', sharpe_a)

b = np.array([-0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
              -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5])
print('b = ', b)
mean_b = np.mean(b)
print('mean_b = ', mean_b)
std_b = np.std(b)
print('std_b = ', std_b)
sharpe_b = mean_b / std_b * np.sqrt(20)
print('sharpe_b = ', sharpe_b)

cor_ab = np.corrcoef(a, b)[0][1]
print('cor_ab = ', cor_ab)

c = a + b
print('c = ', c)
mean_c = np.mean(c)
print('mean_c = ', mean_c)
std_c = np.std(c)
print('std_c = ', std_c)
sharpe_c = mean_c / std_c * np.sqrt(20)
print('sharpe_c = ', sharpe_c)

b[0] = 0.5
b2 = b
print('b2 = ', b2)
mean_b2 = np.mean(b2)
print('mean_b2 = ', mean_b2)
std_b2 = np.std(b2)
print('std_b2 = ', std_b2)
sharpe_b2 = mean_b2 / std_b2 * np.sqrt(20)
print('sharpe_b2 = ', sharpe_b2)

cor_ab2 = np.corrcoef(a, b2)[0][1]
print('cor_ab2 = ', cor_ab2)

c2 = a + b2
print('c2 = ', c2)
mean_c2 = np.mean(c2)
print('mean_c2 = ', mean_c2)
std_c2 = np.std(c2)
print('std_c2 = ', std_c2)
sharpe_c2 = mean_c2 / std_c2 * np.sqrt(20)
print('sharpe_c2 = ', sharpe_c2)
(2016/11/15更新)

トレード戦略の分類

トレード戦略はトレーダーの数だけ存在する、というより、1人で複数の戦略を持つであろうことを考えると、トレーダーの数以上に存在するのだろう。それらを特徴に基づいて分類するにしても、なかなか大変なことである。下のSlideShareの4ページでは5つの基本的なクオンツ戦略に分類しているのが参考になる。

http://www.slideshare.net/JessStauth/d-30965323

これによると、戦略は

  1. 平均回帰戦略:上がるものは下がる。

  2. モメンタム戦略:トレンドは友である。

  3. バリュー戦略:安く買って高く売る。

  4. センチメント戦略:噂で買って事実で売る。

  5. 季節性戦略:5月に売る。

に分類されている。

続くページでは具体例を紹介しながら各戦略について説明されているが、ここでは私の独断と偏見による解釈を用いて、各戦略について簡単に説明する。

平均回帰戦略(上がるものは下がる)

上がるものも永遠に上がり続けることはない。いつかは必ず下がるものである。下がるものも永遠に下がり続けることはない。いつかは必ず上がるものである。

上がったものは下がり、下がったものは上がって、いずれ平均に戻ってくる。そこで、平均より下がれば買い、上がれば売る。これが平均回帰戦略である。ぐだぐだ書いたが、要は逆張りである。

ところで、平均回帰について説明すると、ならば平均の下で買い、上で売れば必ず勝てるのではないか、と勘違いする人が時々いるが、実際にはそうはいかない。平均自体も動くので、平均の下で買っても価格が平均に戻ったときには平均は買った価格より下になっていることもあれば、平均の上で売っても価格が平均に戻ったときには平均は売った価格より上になっていることもあり、そのような場合は負けとなる。

平均回帰戦略で勝つためには価格がある程度、平均から乖離しており、かつ平均の動きが水平に近くなるタイミングを測る必要がある。

モメンタム戦略(トレンドは友である)

トレンドは友、というのはtrendとfriendをかけた洒落だが、米国の投資家ジョージ・ソロスの言葉らしい。別に誰の言葉でも構わないが、トレンドとは仲良くしろ、逆らうな、従え、ということのようだ。つまりはトレンドフォロー、順張りである。

平均回帰戦略の逆で、上がれば、その勢い、つまりモメンタムに付いて行って買い、下がれば、そのモメンタムに付いて行って売るのである。では、順張りと逆張り、どちらの戦略が正しいのだろうか。

時々、順張りが正しく、逆張りは間違っている、というような意見を見かけるが、それは違うと私は思う。値動きというのは時には平均回帰的であり、時にはモメンタム的であるものだ。したがって状況に合った戦略を採用しなければならない。言うは易く行うは難し、だが。

バリュー戦略(安く買って高く売る)

「安く買って高く売る」を「下がったら買って上がったら売る」と解してはいけないのだろう。それだと平均回帰戦略と変わらない。「価格が本来の価値より安ければ買い、高ければ売る」と解すべきなのだろう。

本来の価値を知るためには価格以外の指標が必要である。この辺が過去の価格さえ分かればよい平均回帰戦略との違いである。FXの場合、各国の経済指標などを見ることになるのだろうが、少なくとも短期トレードではこれらの指標は使いにくい。

私は取引する通貨ペア以外の通貨ペアの価格を用い、取引する通貨ペアのあるべき価格を算出して、それより高いか安いかで売買するという手法をバリュー戦略としてもいいのではないかなと考えている。

センチメント戦略(噂で買って事実で売る)

「噂で買って事実で売る」とは、例えば米国の利上げ観測が持ち上がったらドルが高くなるだろうと予測して買い、実際に利上げが決まったらもはやこれ以上は高くならないだろうと予測して売る、といったような戦略である。

もし、これをシステムトレードに導入するのであれば、価格などを用いた定量分析だけではなく、テキストなどを用いた定性分析も必要になるだろう。

季節性戦略(5月に売る)

「5月に売る」というのは株価は5月以降に下がる傾向があるので、5月になったら売るということである。実際に5月以降に下がる傾向があるのかは怪しいが、年、四半期、月、週、日などを通した周期性があると考えて、それに基づいた売買を行うのが季節性戦略である。

(2016/09/15更新)

時刻効果を用いた季節性戦略

時刻効果とは時刻が価格変動に対して与える効果のことである。例えば、ある時刻では上昇(下落)する傾向がある、ボラティリティが大きくなる(小さくなる)傾向がある、などである。

日中効果と呼ぶほうが一般的なようにも思うが、それはどちらかというと昼(取引時間)と夜(取引時間外)に着目した呼び方であるように思われる。ここでは昼、夜というくくりではなく、時刻に着目することとする。

それはさて、戦略はtime_of_day_effect、通貨ペアはUSDJPY、足の種類は60分足、期間は2012年1月1日から2015年12月31日まで、スプレッドは0.4pipsという設定でウォークフォワードテストを行った。

トレードルール

time_of_day_effectのトレードルールは以下の通りである。

買いエントリー

○下落傾向のある時間帯から上昇傾向のある時間帯に移行したとき。

買いエグジット

○上昇傾向のある時間帯から下落傾向のある時間帯に移行したとき。

売りエントリー

○上昇傾向のある時間帯から下落傾向のある時間帯に移行したとき。

売りエグジット

○下落傾向のある時間帯から上昇傾向のある時間帯に移行したとき。

備考

①24時間のうち、下落傾向のある時間帯から上昇傾向のある時間帯に移行する時刻を1つ、上昇傾向のある時間帯から下落傾向のある時間帯に移行する時刻を1つ選び、1日に2回ドテンする。

②3月から10月までを夏時間とみなして調整した。

ウォークフォワードテストの結果は年率15.73%、シャープレシオ1.42であった。

ところで、2015年1月1日から2015年12月31日まで適用して最適化したところ、日本時間の10時から売り、15時から買いという結果になり、日本の株式市場の取引時間とほぼ一致している。買いから売りに転じる時間が10時で日本の株式市場が始まる9時より1時間遅れているが、仲値が10時で、10時までの仲値買いがあることを考えれば納得のいく結果である。

検証ではウォークフォワードテストを行ったが、最適化された時刻には若干のずれがあり、パフォーマンスもやや劣化している。

ウォークフォワードテストではインサンプル期間のトレンドに影響を受けやすい。例えば期間中に上昇(下落)トレンドがあれば買い(売り)の時間が長くなり、売り(買い)の時間が短くなる傾向が出てしまうだろう。正確を期するのであれば、トレンドを除去した上で最適化するべきかもしれない。

サンプルプログラム

①以下のプログラムをSpyderの「エディタ」にコピー&ペーストし、ファイル名を「time_of_day_effect.py」として「~/py」フォルダーに保存する。

# coding: utf-8
import forex_system as fs
import numpy as np
import pandas as pd

# パラメータの設定
UP = 8
DOWN = 3
PARAMETER = [UP, DOWN]
# 最適化の設定
START_UP = 0
END_UP = 23
STEP_UP = 1
START_DOWN = 0
END_DOWN = 23
STEP_DOWN = 1
RRANGES = (
    slice(START_UP, END_UP, STEP_UP),
    slice(START_DOWN, END_DOWN, STEP_DOWN),
)

def strategy(parameter, symbol, timeframe):
    '''戦略を記述する。
    Args:
        parameter: パラメーター。
        symbol: 通貨ペア。
        timeframe: 期間。
    Returns:
        シグナル。
    '''
    # パラメータを格納する。
    up = int(parameter[0])
    down = int(parameter[1])
    # 戦略を記述する。
    close = fs.i_close(symbol, timeframe, 0)
    month = fs.time_month(close.index)
    hour = fs.time_hour(close.index)
    buy = pd.Series(index=close.index)
    sell = pd.Series(index=close.index)
    if up < down:
        buy[(month >= 3) & (month < 11)] = ((hour >= (up + 1) % 24) &
            (hour < (down + 1) % 24)) * 1
        buy[(month < 3) | (month >= 11)] = ((hour >= up) & (hour < down)) * 1
        buy = buy.fillna(0)
        sell[buy != 1] = -1
        sell = sell.fillna(0)
    elif up > down:
        sell[(month >= 3) & (month < 11)] = ((hour >= (down + 1) % 24) &
            (hour < (up + 1) % 24)) * (-1)
        sell[(month < 3) | (month >= 11)] = (((hour >= down) & (hour < up)) *
            (-1))
        sell = sell.fillna(0)
        buy[sell != -1] = 1
        buy = buy.fillna(0)
    else:
        buy = pd.Series(np.zeros(len(close)), index=close.index)
        sell = pd.Series(np.zeros(len(close)), index=close.index)
    signal = buy + sell
    signal = signal.astype(int)

    return signal

②以下のコマンドをSpyderの「IPython console」にコピー&ペーストして「Enter」キーを押す。

%run -t ~/py/backtest.py --ea1 time_of_day_effect --symbol1 USDJPY --spread1 4 --timeframe 60 --start 2012.01.01 --end 2015.12.31 --optimization 2
(2016/11/21更新)