ストキャスティクスをTA-Libで実装してみた　#QuantX

##まず自己紹介から
某理系大学で電気を専攻してる大学２年生のkatakyoです。
Pythonも金融の知識もガチ初心者です。
最近SmartTrade社の方でインターン始めました。

##この記事の対象者
・TA-Libにあまり触ったことない方
・別の金融指標を使ってみたいという方
・ファンダメンタル分析もそろそろしてみたい方
です。

##QuantX Factoryって何？
URL:[QuantX Factory ホームページ](https://factory.quantx.io/)
開いてみるとこんな画面が出てきます。
<img width="1432" alt="スクリーンショット 2018-11-28 18.14.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/586e48c4-b7c0-87ca-aaca-bd7a9b711c6f.png">

**QuantX Factoryとは**
ブラウザ上で動かせる、株式や仮想通貨などの売買ルール(アルゴリズム)の作成、販売ができるシステムトレードプラットフォームです。pythonというプログラミング言語を用いて動かします。

開発デモを体験するというボタンをクリックするとログインしてくださいという画面がでます。
Facebook,Googleアカウントなどで簡単にログインできるのでログインしてください！！

##今回のゴール
ストキャスティクスの基礎を理解すること。
2種類のストキャスティクスをQuantX上で描画、売買シグナルを出すこと。
Ta-Libの扱いになれること。
現実的な取引を行うこと。
ファンダメンタル分析も少ししてみること
この5つが今回の目標です！

##ストキャスティクスとは？
ストキャスティクスとは一定期間の高値と安値を活用して、株価の「売られすぎ」、「買われすぎ」を判断するための指標の一つです。現状の価格が一定期間の高値および安値と比較して、終値どの位置にあるかで算出されます。

##２種類のストキャスティクス
「％K」と「％D」の2本のラインを利用した、ファーストストキャスティックスと、「%D」と「Slow％D」の2本の線を利用したスローストキャスティクスの2種類がありますが、ファーストストキャスティクスは、相場の動きに素早く反応するため、短期売買向きでダマシも多いのが欠点です。それを補う役割を果たすのがスローストキャスティクスで、一般的にはこちらを利用することが多いです。
なので今回はスローストキャスティクスをメインに解説して行きます。

##ストキャスティクスの計算方法

```
%K =（直近の終値-過去n日間の最安値）/（過去n日間の最高値-過去n日間の最安値）× 100
%D = m日の%Kの単純移動平均
Slow%D = x日の%Dの単純移動平均

追記
Slow%K = %D
```

##スローストキャスティクスの売買シグナル

###買いサイン
Slow％D」が0～20％にある時は、売られすぎゾーンと見て「買いサイン」と判断します。
また、0～20％で「％D」ラインが「Slow％D」を下から上に抜ける（ゴールデンクロス）で強い買いシグナルと見ます。

###売りサイン
Slow％D」が80～100％にある時は、買われすぎゾーンと見て「売りサイン」と判断します。また、80～100％で「%D」ラインが「Slow％D」を上から下に抜ける（デッドクロス）で強い売りシグナルと見ます。

<img width="872" alt="スクリーンショット 2019-01-23 16.02.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/2b1c9986-7a31-0fd1-c2cd-97c05c147123.png">

今回はこのようなシグナルが出るようなアルゴリズムを目指します！！




##コード記述の前に
###銘柄選び
今回はファンダメンタル分析もやっていこうと思います。
[バフェット・コード](https://www.buffett-code.com/)というサイトでスクリーニングを行います。
10銘柄ほど選んでいきます。

今回やったこと
・PER×PBR≦10倍
・配当利回り(会予）≧2%
・ROA≧10%

```python:symbol.py
            "jp.stock.1514", #住石HD
            "jp.stock.1808", #長谷工コーポレーション
            "jp.stock.2121", #ミクシィ
            "jp.stock.4042", #東ソー
            "jp.stock.4367", #広栄化学工業
            "jp.stock.5542", #新報国製鉄
            "jp.stock.5967", #TONE
            "jp.stock.6384", #昭和真空
            "jp.stock.6728", #アルバック
            "jp.stock.7190", #マーキュリアインベストメント
```
実はファンダメンタルはシグナルデータとしても扱えます！！
参考はコチラの記事にて
https://qiita.com/Ric418/items/8fb96cac756c895d770e

###シグナル
今回は以下のシグナルを&で繋ぎます。

・%Dの一本のみで売られすぎか買われすぎか判断する。
・%Dとスロー%Dを日本の移動平均線の様に考え、%Dがスロー%Dを上抜けたらゴールデンクロスで買い、%Dがスロー％Dを下抜けたらデッドクロスで売り

今回は売られすぎゾーンにおけるゴールデンクロス、買われすぎゾーンにおけるデッドクロスのみにシグナルを出していきます。


##コードの実装

公開コードは以下のリンクになります。
https://factory.quantx.io/developer/92b0362e75764499a69c37dd8317f9a5
cloneしてみてください。

```python:stoch.py
import talib as ta 
import pandas as pd 
import numpy as np 

#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.1514", #住石HD
            "jp.stock.1808", #長谷工コーポレーション
            "jp.stock.2121", #ミクシィ
            "jp.stock.4042", #東ソー
            "jp.stock.4367", #広栄化学工業
            "jp.stock.5542", #新報国製鉄
            "jp.stock.5967", #TONE
            "jp.stock.6384", #昭和真空
            "jp.stock.6728", #アルバック
            "jp.stock.7190", #マーキュリアインベストメント
            
          ],
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    #シグナル定義
    def _mysignal(data):
      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      hp = data["high_price_adj"].fillna(method='ffill')
      lp = data["low_price_adj"].fillna(method='ffill')
      cp = data["close_price_adj"].fillna(method='ffill')

      #スローストキャスティクスの設定
      #データの入れ物を用意
      slowK = pd.DataFrame(data=0,columns=[], index=cp.index)
      slowD = pd.DataFrame(data=0,columns=[], index=cp.index)

      #TA-Libによる計算
      for (sym,val) in cp.items():
        slowK[sym], slowD[sym] = ta.STOCH(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), 
                                fastk_period=20, 
                                slowk_period=3, 
                                slowd_period=3)
      
      #売買シグナル
      buy_sig = (slowK > slowD) & (slowK.shift(1) < slowD.shift(1)) & (slowD < 20)
      sell_sig = (slowK < slowD) & (slowK.shift(1) > slowD.shift(1)) & (slowD > 80)
      
      return {
        "%D":slowK, 
        "スロー％D": slowD, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,        
        }

    # シグナル登録
    ctx.regist_signal("my_signal", _mysignal)

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

    # 買いシグナル
    df_buy = df[df["buy:sig"]]
    if not df_buy.empty:
      for (sym, val) in df_buy.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(0.20, 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)
        
    #利益確定売り　損切り
    done_syms = set([])
    for (sym,val) in ctx.portfolio.positions.items():
        returns = val["returns"]
        #ctx.logger.debug("%s %f" % (sym, returns))
        if returns < -0.03:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="損切り(%f)" % returns)
          done_syms.add(sym)
        elif returns > 0.05:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
          done_syms.add(sym)
```

##コード解説

###基本設定
####【1~3行目】ライブラリーのimport 

```python:stoch.py
import talib as ta 
import pandas as pd 
import numpy as np 
```

talib pandas numpyをimportして使えるようにします。
talibはta pandasはpd numpyはnpとして今後扱っていきます。

####【5~32行目】初期化 （トレードの基本設定）

```python:stoch.py
#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.1514", #住石HD
            "jp.stock.1808", #長谷工コーポレーション
            "jp.stock.2121", #ミクシィ
            "jp.stock.4042", #東ソー
            "jp.stock.4367", #広栄化学工業
            "jp.stock.5542", #新報国製鉄
            "jp.stock.5967", #TONE
            "jp.stock.6384", #昭和真空
            "jp.stock.6728", #アルバック
            "jp.stock.7190", #マーキュリアインベストメント
          ],
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )
```
初期化では、アルゴリズムで利用する市場（日本株等）、トレードする銘柄、利用する値（終値、高値など）を設定します。
6行目で初期化用の関数を定義
8行目でプログラムのログ出力を行うコード(バックテストを行うときに必要）
9行目以下にトレードの基本設定を行います。
10行目のtarget="jp.stock.daily"で日足の日本株のデータを使うことを宣言します。
11行目のchannels以下で実際にデータを入れていきます。
13行目で"symbols"と書かれてありますが,{}に銘柄のデータを入れます。
今回は14~23行目まで"jp.stock."銘柄番号"" で使用する銘柄のデータを入れています。
入れた銘柄は先程スクリーニングした銘柄です。
データがない企業もありますので、バックテスト後エラーが起きた場合はここを見るといいと思います。
25行目に"columns"と書かれてありますが,{}に必要なデータ(終値など）を入れます。
今回はスローストキャスティクスに高値、安値、終値のデータが必要なので、これらのデータを入れます。

###シグナル定義
####【34~39行目】使用するデータ量の設定

```python:sma.py
    #シグナル定義
    def _mysignal(data):
      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      hp = data["high_price_adj"].fillna(method='ffill')
      lp = data["low_price_adj"].fillna(method='ffill')
      cp = data["close_price_adj"].fillna(method='ffill')

```
35行目では売買シグナルを生成する関数の定義しています。
37~39行目では各銘柄の高値、安値、終値(株式分割調整後)のデータを取得します。今回、高値はhp、安値はlp、終値はcpとして定義しました。
データではたまに欠損値（値がNaNとなり、計算できない値）が含まれる場合があります。欠損値があると計算ができません。
そこで、fillna(method='ffill')を使うとNaNがあった場合に、さまざまな方法で自動的に補完をしてくれるようになります。

####【42~45行目】データの容れ物を用意
```python:sma.py
      #スローストキャスティクスの設定
      #データの入れ物を用意
      slowK = pd.DataFrame(data=0,columns=[], index=cp.index)
      slowD = pd.DataFrame(data=0,columns=[], index=cp.index)
```
今回スローストキャスティクスを計算する上で%Dとスロー%Dの値が必要なので、それらのデータの容れ物を作成します。
そのデータを格納するための容れ物をDataFrameというオブジェクトを用い、作ります。
今回はSlow％K= %Dなので
・%DをslowK
・スロー%DをslowD
としています。

####【47~54行目】TA-Libによる計算
```python:sma.py
      #TA-Libによる計算
      for (sym,val) in cp.items():
        slowK[sym], slowD[sym] = ta.STOCH(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), 
                                fastk_period=20, 
                                slowk_period=3, 
                                slowd_period=3)
```

配列の際データがうまく使えるように.values.astype(np.double)というメソッドを用いたコードを記述しています。別のデータを入れる場合にもこのメソッドは同様につけてください。（つけないと多分エラーが出ます）
TA-Libのドキュメントでスローストキャスティクスは終値と安値、高値、期間が必要だったので記述します。
すると計算結果が返り値として出てきます。
[TA-Lib Documentation](https://cryptotrader.org/talib)

####【56~58行目】売買シグナルの定義
```python:sma.py
      buy_sig = (slowK > slowD) & (slowK.shift(1) < slowD.shift(1)) & (slowD < 20)
      sell_sig = (slowK < slowD) & (slowK.shift(1) > slowD.shift(1)) & (slowD > 80)
      
```
売買シグナルを定義します。

**%Dの一本のみで売られすぎか買われすぎか判断する**。
(slowD < 20)、(slowD < 80)でslowDが20%より下回っていたら買われすぎなので売り、slowDが80%より上回っていたら売られすぎなので買いという逆張りのシグナルを出します。

**%Dとスロー%Dを日本の移動平均線の様に考え、%Dがスロー%Dを上抜けたらゴールデンクロスで買い、%Dがスロー％Dを下抜けたらデッドクロスで売り**
(slowK > slowD) & (slowK.shift(1) < slowD.shift(1),(slowK < slowD) & (slowK.shift(1) > slowD.shift(1))で前日のslowK,slowDの値と比較しゴールデンクロス、デッドクロスでシグナルを出します。

####【60~65行目】%Dと売買シグナルの可視化
```python:sma.py
   return {
        "%D":slowK, 
        "スロー％D": slowD, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,        
        }
```
return内にシグナル定義部分で定義した変数を入れ、バックテスト後可視化できるようにしましょう。

####【67~68行目】移動平均線と売買シグナルの可視化
```python:sma.py
     # シグナル登録
    ctx.regist_signal("my_signal", _my_signal)
```
シグナル登録し、シグナルは生成されました！！

###ポジションの決定

####【70~71行目】日ごとの処理を行う関数の定義
```python:sma.py
def handle_signals(ctx, date, current):
    df = current.copy()
```
バックテストを行う際、同じ処理を何度も行う必要があります。
そこで日ごとに呼び出される関数を定義します。
例えば100日分のデータのバックテストをやる場合、100回呼び出される事になります。 ここで株をどの位売買するかの決定や損切り、利益確定売りを指定します。 この関数はエンジンから直接呼び出されます。

dateにはdatetime.datetime型で対応する日付が入っています
currentは、dateの当日のデータとシグナルを含んだ pandas.DataFrame オブジェクト
ctxはnitialize や handle_signals の引数として渡されるオブジェクト

[詳しくはコチラ](https://determined-feynman-fb5a05.netlify.com/ja/#handle-signals)

####【72~79行目】買いの数量の設定
```python:sma.py
    # 買いシグナル
    df_buy = df[df["buy:sig"]]
    if not df_buy.empty:
      for (sym, val) in df_buy.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(0.20, comment = msg)
```
先程定義した関数dfにbuy:sigのデータを入れ、取引を行います。
今回はorder_target_percent(amount, comment)というメソッドを用います。
この銘柄の総保有額が総資産評価額(現金+保有ポジション評価額)に対して指定の割合となるように注文を行ないます。 amountには割合(例:5%なら0.05)を指定します。
よって今回は総資産の20%の買いを入れます。

####【81~87行目】売りの数量の設定
```python:sma.py
    # 売り（ポジションクローズ）シグナル
    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)
```
同様に売りの数量も決定していきます。
今回は売りすぐなるが出たら全て売るという取引にしています。

####【89~101行目】手仕舞いの設定
```python:sma.py
    #利益確定売り　損切り
    done_syms = set([])
    for (sym,val) in ctx.portfolio.positions.items():
        returns = val["returns"]
        #ctx.logger.debug("%s %f" % (sym, returns))
        if returns < -0.03:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="損切り(%f)" % returns)
          done_syms.add(sym)
        elif returns > 0.05:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
          done_syms.add(sym)
```
リスク回避のため(このままだとMaxdrawdownがとんでもないので)損切り、利益確定売りのサインも出します。
今回かなり慎重に-3%で損切り +5%で利益確定売りにしました。

##バックテスト結果
<img width="907" alt="スクリーンショット 2019-01-23 15.26.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/3ca5883f-362c-dead-b93a-c88f3aa5b189.png">

三年で損益率50%でした。
手仕舞いを弄れば80%ほど行きました。
ここ一年で全く利益を出せていないのが痛いところ。
<img width="874" alt="スクリーンショット 2019-01-23 15.41.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/e5537a65-5525-38ca-0486-af8554525f13.png">
%D、スロー％Dともにちゃんと描画されていますね！
期間を変えて最適化すればもっと良い結果が出るかもしれません。

##同じ条件でファストストキャスティクスも実装してみる。
###シグナル
%Kと%Dを日本の移動平均線の様に考え、%Kが%Dを上抜けたらゴールデンクロスで買い、%Kが％Dを下抜けたらデッドクロスで売り

##ファストストキャスティクスのコードの実装
[コードはコチラ](https://factory.quantx.io/developer/f46aeafb06144e32970b75dda73281b5)

```python:stochf.py
import talib as ta 
import pandas as pd 
import numpy as np 

#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.1514", #住石HD
            "jp.stock.1808", #長谷工コーポレーション
            "jp.stock.2121", #ミクシィ
            "jp.stock.4042", #東ソー
            "jp.stock.4367", #広栄化学工業
            "jp.stock.5542", #新報国製鉄
            "jp.stock.5967", #TONE
            "jp.stock.6384", #昭和真空
            "jp.stock.6728", #アルバック
            "jp.stock.7190", #マーキュリアインベストメント
            
          ],
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    #シグナル定義
    def _mysignal(data):
      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      hp = data["high_price_adj"].fillna(method='ffill')
      lp = data["low_price_adj"].fillna(method='ffill')
      cp = data["close_price_adj"].fillna(method='ffill')

      #ファストストキャスティクスの設定
      #データの入れ物を用意
      fastK = pd.DataFrame(data=0,columns=[], index=cp.index)
      fastD = pd.DataFrame(data=0,columns=[], index=cp.index)

      #TA-Libによる計算
      for (sym,val) in cp.items():
        fastK[sym], fastD[sym] = ta.STOCHF(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), 
                                fastk_period=20, 
                                fastd_period=3,)
      
      #売買シグナル
      buy_sig = (fastK > fastD) & (fastK.shift(1) < fastD.shift(1)) 
      sell_sig = (fastK < fastD) & (fastK.shift(1) > fastD.shift(1))
      
      return {
        "%K":fastK, 
        "%D": fastD, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,        
        }

    # シグナル登録
    ctx.regist_signal("my_signal", _mysignal)

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

    # 買いシグナル
    df_buy = df[df["buy:sig"]]
    if not df_buy.empty:
      for (sym, val) in df_buy.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(0.20, 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)
        
    #利益確定売り　損切り
    done_syms = set([])
    for (sym,val) in ctx.portfolio.positions.items():
        returns = val["returns"]
        #ctx.logger.debug("%s %f" % (sym, returns))
        if returns < -0.03:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="損切り(%f)" % returns)
          done_syms.add(sym)
        elif returns > 0.05:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
          done_syms.add(sym)
```
###バックテスト結果
<img width="817" alt="スクリーンショット 2019-01-23 16.36.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/221d33c2-9ec4-3cde-0c31-449bcdf31f43.png">
変動が激しいですね。
ファストストキャスティクスはダマシが多く長期のトレードには向いてないようです。
<img width="808" alt="スクリーンショット 2019-01-23 16.41.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/c935e2cf-59ca-03b2-9d1e-40c4109ed6ef.png">
シグナルも気持ち悪いくらい出てますね。
QuantXにはスローストキャスティクスの方が向いてそうですね。

##おまけ
ストキャスティクスはダマシが多い指標なので
トレンドの分析を75日移動平均線に任せてみました。
[コードはコチラ」(https://factory.quantx.io/developer/aef9ce1892744e769dab980235d78f98)
####加えた条件
前日の移動平均線の値と比較し値が上昇していれば買いシグナル、減少していれば売りシグナルという条件を加えてみました。

```python:sma-stoch.py
import talib as ta 
import pandas as pd 
import numpy as np 

#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.1514", #住石HD
            "jp.stock.1808", #長谷工コーポレーション
            "jp.stock.2121", #ミクシィ
            "jp.stock.4042", #東ソー
            "jp.stock.4367", #広栄化学工業
            "jp.stock.5542", #新報国製鉄
            "jp.stock.5967", #TONE
            "jp.stock.6384", #昭和真空
            "jp.stock.6728", #アルバック
            "jp.stock.7190", #マーキュリアインベストメント

          ],
          "columns": [
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    #シグナル定義
    def _mysignal(data):
      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      hp = data["high_price_adj"].fillna(method='ffill')
      lp = data["low_price_adj"].fillna(method='ffill')
      cp = data["close_price_adj"].fillna(method='ffill')

      #スローストキャスティクスの設定
      #データの入れ物を用意
      slowK = pd.DataFrame(data=0,columns=[], index=cp.index)
      slowD = pd.DataFrame(data=0,columns=[], index=cp.index)
      sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      
      #TA-Libによる計算
      for (sym,val) in cp.items():
        slowK[sym], slowD[sym] = ta.STOCH(hp[sym].values.astype(np.double), 
                                lp[sym].values.astype(np.double), 
                                cp[sym].values.astype(np.double), 
                                fastk_period=20, 
                                slowk_period=3, 
                                slowd_period=3)
                                
      for (sym,val) in cp.items():
        sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=75)
      

      
      #売買シグナル
      buy_sig = (slowK > slowD) & (slowK.shift(1) < slowD.shift(1)) & (slowD < 20) & (sma > sma.shift(1))
      sell_sig = (slowK < slowD) & (slowK.shift(1) > slowD.shift(1)) & (slowD > 80) & (sma < sma.shift(1))

      return {
        "sma":sma,
        "%D":slowK, 
        "スロー％D": slowD, 
        "buy:sig":buy_sig,
        "sell:sig":sell_sig,        
        }

    # シグナル登録
    ctx.regist_signal("my_signal", _mysignal)

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

    # 買いシグナル
    df_buy = df[df["buy:sig"]]
    if not df_buy.empty:
      for (sym, val) in df_buy.iterrows(): 
        sec = ctx.getSecurity(sym)
        msg = "買いシグナル"
        sec.order_target_percent(0.20, 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)

    #利益確定売り　損切り
    done_syms = set([])
    for (sym,val) in ctx.portfolio.positions.items():
        returns = val["returns"]
        #ctx.logger.debug("%s %f" % (sym, returns))
        if returns < -0.03:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="損切り(%f)" % returns)
          done_syms.add(sym)
        elif returns > 0.05:
          sec = ctx.getSecurity(sym)
          sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
          done_syms.add(sym)
```
##結果
<img width="812" alt="スクリーンショット 2019-01-25 16.53.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/ba183700-5c38-2cef-0927-1ed6de2d611b.png">

ドローダウンとベータが改善されましたが損益率、アルファが下がってしましました。
銘柄決定がよくないのではと思い。

```
銘柄変えてみました
            "jp.stock.2317", 
            "jp.stock.3150", 
            "jp.stock.3665", 
            "jp.stock.3687",
            "jp.stock.3836", 
            "jp.stock.3923", 
            "jp.stock.3962",
            "jp.stock.6035",
            "jp.stock.6046", 
            "jp.stock.6050",
            "jp.stock.6055", 
            "jp.stock.6067",
            "jp.stock.6200", 
            "jp.stock.6920",

```

これでやってみました。
[コードはコチラ](https://factory.quantx.io/developer/basic-info/e51b5cf4d2e1430aad33c7c6d784678c)
<img width="812" alt="スクリーンショット 2019-01-25 17.57.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/318447/59b51b69-01ef-ff00-2f91-8a2aedb2cd1c.png">
損益率400%越えに!!　（ストキャスティクスだけでやってます。）
銘柄選びって大事ですね。
ただ実際に運用するにあたってはリスクケアなども大事なので損益率だけをみるのは危険だと思います！！


##金融用語まとめ
バックテスト後の上にある金融指標が損益率意外よくわからないなあという方向けです。

[ドローダウン](https://www.nomura.co.jp/terms/japan/to/A01914.html)
[ボラティリティ](https://www.nomura.co.jp/terms/japan/ho/volatility.html)
[アルファ](https://www.nomura.co.jp/terms/japan/a/alpha.html)
[ベータ](https://www.nomura.co.jp/terms/japan/he/beta.html)

##終わりに
最近テスト大丈夫かなぁと危機感を感じております。
QuantXは良い気分転換になりますね。

##予告
近日大学生向けにイベント開きます！！（イエイ！）

##宣伝
勉強会やってます！
日時：毎週金曜日19時〜
場所：神田　千代田共同ビル４階　SmartTrade社オフィス
内容：初心者(プログラミングってものを知らなくてもOK)向けに初心者(私とか)がこんな内容をハンズオン(一緒にやる事)で解説しています
備考：猛者の方も是非御鞭撻にいらして下さい、そして開発・伝導者になりましょう！

もくもく会もやってます！
日時：毎週水曜日18時〜
場所：神田　千代田共同ビル４階　SmartTrade社オフィス
内容：基本黙々と自習しながら猛者の方に質問して強くなっていく会
備考：お菓子と終わりにお酒を飲みながら参加者と歓談できます！

詳細はこちらだよ
Pythonアルゴリズム勉強会HP：https://python-algo.connpass.com/
(connpassって言うイベントサイトに飛びます）

インターンブログも書いてます！！
インターン活動期や神田メシ（？）なども書いたりしてます！
興味あれば是非みてください！！
http://intern.quantx.io/


##免責注意事項
このコードや知識を使った実際の取引で生じた損益に関しては一切の責任を負いかねますので御了承下さい