新高値更新のアルゴリズム #QuantX

## 新高値更新
ある株の銘柄の本日の高値が、過去の一定期間における最高値を更新した場合、相場の一段高を暗示し、買いシグナルになるそうです．これを新高値更新と呼ぶそうです。
今回は、これを使ってQuantXでシミュレーションをしてみます。

## シグナル
ここでは本日の高値と過去１０日間の最高値を見て、新高値更新の判定をし、取引シグナルとすることにします．株価の比較には、株式分割調整後のものを用います。
ただし，本日の高値が過去１０日間の最高値になっていても、過去5日間（＝ホールド期間）に既にも同じことが起きていた場合にはシグナルとはしません。

## 手仕舞い
シグナルが出てから５日間ホールドして、クローズすることにします。


## コード

```python

def initialize(ctx):
    # 設定
    ctx.logger.debug("initialize() called")
    
    # 過去何日間を観察するか
    ctx.high_term = 10
    # ポジションに対して何％持つか 
    ctx.target = 0.5 
    # ポジションを何日ホールドするか
    ctx.holding_days = 5 
    
    ctx.configure(
      channels={          # 利用チャンネル
        "jp.stock": {
          "symbols": [
            "jp.stock.1305",
            "jp.stock.9984",
            "jp.stock.9983",
            "jp.stock.7201",
            "jp.stock.9201",
            "jp.stock.9202",
            "jp.stock.7203"
          ],
          "columns": [
            "high_price_adj",]}})    # 高値(株式分割調整後)

    def _BREAK_NEW_HIGH(data):
      
      # 欠損値を埋める
      hp = data["high_price_adj"].fillna(method="ffill")
      # 過去10日間における最高値を取得
      new_max = hp.rolling(window=ctx.high_term, center=False).max()
      # その最高値が今日の高値と同じかどうかの真偽値
      today_is_new_high = new_max == hp
      # 今日が過去10日間における最高値であり，かつ，過去５日間において最高値が発生していないという真偽値
      buy_signal = (today_is_new_high) & (today_is_new_high.rolling(window=ctx.holding_days, center=False).sum() == 1)
      
      # pd.Serieseの shift 関数を使って5日前のbuy_signalのシグナルを取得．
      # ここがTrueであれば5日前に取引したという事なので，この日にポジションを閉じる
      # （memo 参照）
      close_signal = buy_signal.shift(ctx.holding_days)
      

      return {
        "New High":new_max, 
        "buy:sig": buy_signal,
        "close:sig": close_signal,
        }

    # シグナル登録
    ctx.regist_signal("BREAK_NEW_HIGH", _BREAK_NEW_HIGH)

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(): 
        #ctx.logger.info(val)
        sec = ctx.getSecurity(sym)
        # New High と 過去10日間の High が本当に同じかどうか確認したかったのでコメントに入れた．
        msg = "買いシグナル: Today's High {0}, Rolling High {1}".format(val["high_price_adj"], val["New High"],)
        sec.order_target_percent(ctx.target, comment= msg)
  
  
    # # ポジションクローズ
    df_close = df[df["close:sig"]]
    if not df_close.empty:
      for (sym, val) in df_close.iterrows(): 
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment= "position close")
```

## memo 

### shift について
[shift](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.shift.html)は，データをｎ行ずらすときに使います．コードでは，`buy_signal`を5シフトした pd.Serise データを `close_signal` とすることで，5日間ホールドして手仕舞うというシグナルを作っています．

イメージはこんな感じです．

![2018-07-27-18:00:25.jpg](https://qiita-image-store.s3.amazonaws.com/0/14019/b75d93e3-c8ad-026b-63d5-4a1676994d11.jpeg)


## 結果

![2018-07-27-18:11:51.jpg](https://qiita-image-store.s3.amazonaws.com/0/14019/03a9a56f-1962-d51e-7179-30aa4e8f0dc3.jpeg)



## 感想など
+ 銘柄選定はQuantXプロジェクトを新規作成すると自動生成されるサンプルコードに使われている銘柄をそのまま使っています．
+ 高値で見るのではなく，終値で見たほうがいいのでは？と思いました．
+ `shift` とは仲良くしていきたい．
+ 台風12号が心配

## 免責注意事項
+ このコードに基づき投資した結果、損害が発生しても，一切責任を持ちません．
+ このコードが正しく機能する保証は一切致しません．
+ このアルゴリズムを勧めているわけではありません．あくまで python のサンプルコードとして掲載しているだけです．