Help us understand the problem. What is going on with this article?

[注意]100%勝ってしまうシグナル #QuantX

More than 1 year has passed since last update.

100% 勝ってしまった

QuantXでアルゴリズムを書く方法を投稿していたのですが,ふと100%勝てるシグナルが書けるんじゃない?と思って書いてみたら書けたというお話です. 

とりあえず結果を.

2018-08-15_15.jpg

天国や:hotsprings:

Look-Ahead Bias

コレは現実のシグナルでは絶対に起きない, Look-Ahead Biasという間違いです.

株価分析を行う上でのルックアヘッドとは,誤って将来の価格を分析対象に入れて予測を行ってしまうことを言います.

QuantXのバックテストでは,(私の想像がただしければ)指定された全期間のヒストリカルデータを取得して売買シグナルを計算し,その後,該当日の買いシグナルおよび売りシグナルに基づいて損益を計算する仕様になっています.

つまり,コードの書き方を間違うと,シグナル計算時に誤って将来のデータが入る可能性があるわけです.

実際のコードがこちらです.

def initialize(ctx):
    # 設定
    ctx.target = 0.10
    ctx.period = 5
    ctx.codes = [1605, 1925, 2503, 4519, 4911, 6301, 6752, 7741, 8001 ]
    ctx.symbol_list  = ["jp.stock.{}".format(code) for code in ctx.codes]


    ctx.configure(
      channels={ 
        "jp.stock": {
          "symbols":ctx.symbol_list,
          "columns": ["close_price_adj",
          ]}})

    def _NOTCORRECT_SIGNAL(data):

      df_close = data["close_price_adj"].fillna(method='ffill')
      df_cheat_close = df_close.pct_change().shift(-2) ## <----- ここ!!!!!!!!!
      buy_sig = df_cheat_close > 0 
      sell_sig = buy_sig.shift(1) == True

      return {
        "cheat":df_cheat_close, 
        "buy:sig": buy_sig, 
        "sell:sig": sell_sig, 

        }

    # シグナル登録
    ctx.regist_signal("NOTCORRECT_SIGNAL", _NOTCORRECT_SIGNAL)

def handle_signals(ctx, date, current):
    df = current.copy()

    # 買いシグナル
    df_long = df[df["buy:sig"]]
    if not df_long.empty:
      for (sym, val) in df_long.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(ctx.target, comment= msg)

    # 売り(ポジションクローズ)シグナル
    df_sell = df[df["sell:sig"]]
    if not df_sell.empty:
      for (sym, val) in df_sell.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "売りシグナル"
        sec.order_target_percent(0, comment= msg)

上記 df_cheat_close = df_close.pct_change().shift(-2)が Look-Ahead 部分です.

df_closeは,pandas.DataFrame型です.メソッドである shift を使うと,データを前後(表形式で見れば上下)に動かすことができます.ただし,Index(ここでは日付)は動きません.

例;

import pandas as pd 
rng = pd.date_range('1/1/2018',periods=4,freq='D')
df = pd.DataFrame({'AAA' : [4,5,6,7], 'BBB' : [10,20,30,40],'CCC' : [100,120,110,150]}, index=rng)

2018-08-15_17.jpg

今回書いたQuantXのコードでは,df_cheat_close = df_close.pct_change().shift(-2)と書くことで,2日後の変化率を取得し,ポジティブであれば,買いシグナルを出すという方法で100%勝てるシグナルを作りました.

QuantXでは,シグナルの算出タイミングと,実際の取引するタイミングは異なります.
シグナルは,今日の終値が確定した後,つまり午後三時の大引け後算出し,取引は翌日の大引け時に行います.

例を上げると,このような日程になります

8月15日 8月16日15時以降 8月17日15時 8月18日15時
Buysig発生 買い取引 評価損益

よって,17日から18日が値上がりすることがわかっていれば,16日にBuyシグナルを出せばよいということになります.
従って,shift(-2)でその情報を得ると,シグナルが出せるわけです.

ぬかよろこびはできます

look-ahead bias は,現実には起きませんが,バックテストでぬかよろこびすることはできます:angel:
みなさんはこんな間違いはしないと思いますが,複雑なアルゴリズムを書いていると,こういうケアレスミスだけど,致命的なミスは入りがちです.shift()メソッドはとても便利ですが,注意してお使い下さい.

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away