6
4

More than 5 years have passed since last update.

移動平均線について その1〜3種類の移動平均線を描画してみる 〜#QuantX

Last updated at Posted at 2019-01-08

まず自己紹介から

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

この記事の対象者

・QuantX初めての方
・TA-Libにあまり触ったことない方
・デフォルトの移動平均線使いたくないという方
・別の金融指標を使ってみたいという方
です。

QuantX Factoryって何?

URL:QuantX Factory ホームページ
開いてみるとこんな画面が出てきます。
スクリーンショット 2018-11-28 18.14.48.png

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

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

今回のゴール

移動平均線の基礎を理解すること。
3種類の移動平均線をQuantX上で描画、売買シグナルを出すこと。
Ta-Libの扱いになれること。
この3つが今回の目標です!

移動平均線とは

「チャート分析は移動平均線に始まり、移動平均線に終わる」「移動平均線を制する者がチャート分析を制する」という言葉があるようにテクニカル分析の基本にして王道のテクニカル分析法。

テクニカル分析法は移動平均線だけでなく、MACD,RSI,ストキャスティクス,一目均衡線など..
ほとんど聞いたことが内容なものも含めると100以上あります。

ただ、トレード経験の長い投資家であるほど基本に立ち返り、移動平均線のようなシンプルな手法を使っているそうです。

テクニカル分析法において、重要なのはどの分析法を使えば、相場が上がる・下がるの予測ができるかエントリーやエグジットがしやすいか、ダマシを回避しやすいかということです。

金融用語解説

・エントリー:取引に参加すること、要は株を購入すること
・エグジット:取引から退場すること、要は株を売却すること
・ダマシ:売買サインが出たものの、相場はそのサインとは全く逆方向に動いていくこと。

移動平均線の役割

移動平均線の最も重要な役割は価格の動きを滑らかにすることです。
これによって上昇トレンドと下降トレンドがよくわかるようになります。
image.png
(画像引用:じぶん銀行

移動平均線の考え方

では移動平均線はどのように求められるのでしょうか?単純移動平均線を例にとって考えてみましょう。
米ドルの終値の5日間移動平均線を考えてみましょう。

 日数  終値 5日間の平均
1日目 110円50銭
2日目 110円90銭
3日目 110円10銭
4日目 109円50銭
5日目 110円20銭 110円24銭
6日目 110円90銭 110円32銭
7日目 110円70銭 110円20銭
5日間の平均=(110円50銭+110円90銭+110円10銭+109円50銭+110円20銭)/5日間

このように計算式は単純です(後述する指数平滑移動平均線は複雑ですが..)
このようにして、1日ごとの新しい日の終値を加えるのと同時に、1日目の終値を外して5日間の平均値を計算し続け平均値を線で結ぶと、5日間移動平均線ができます。

移動平均線の期間

ところで移動平均線を活用する上で何日間の平均をとったらいいのでしょうか?
よくあるチャートツールでは5日間、25(20)日間、75日間、200日間がよく用いられます。
一般的には5日移動平均線のことを「短期線」、25(20)日移動平均線のことを「中期線」、200日移動平均線のことを「長期線」と言います。75日移動平均線に関しては「中期線」「長期線」どちらにカテゴライズするかは人によって違います。

5日間は1週間(7日間)のうち市場が動いていない土日を外したものです。25(20)日は1ヶ月間から土日を外した日数に近く、同様に75日は3ヶ月間、200日は1年間に該当します。

移動平均線の種類

移動平均線には計算方法によって種類がたくさんあります。
その中でも今回は代表的なもの3つをご紹介

単純移動平均線(SMA)

一定期間(n日間)の価格を平均したもので、一般的に移動平均といえば、単純移動平均のことを指します。

n日間の単純移動平均
SMA=(1日目の終値+2日目の終値+3日目の終値+・・・+N日目の終値)/(N日間)

加重移動平均線(WMA)

直近の価格に近いものほど重要度を大きくし一定期間(n日)平均したもので、(例えば、20日の終値加重移動平均の場合、直近価格を20倍し古い価格には1倍して価格を平均したものです。)単純移動平均に比べ直近の価格に対しての反応度が高くなっています。

n日間の加重移動平均
WMA=(1日目の終値x1+2日目の終値x2+3日目の終値x3+・・・+N日目の終値xN/(1+2+3+・・+N)

指数平滑移動平均線(EMA)

最近の価格に比重を置き、過去になればなるほど比重を軽くして平均値を決定します。
比重の減少度合いは「平滑化係数」と呼ばれる0と1の間の値を取る定数α(平滑定数)で決められます。
MACDの計算式によく使われます。

n日間の指数平滑移動平均
1日目=(当日も含め)n日の終値の平均
2日目以降=前日の指数平滑移動平均+α×{当日終値-前日の指数平滑移動平均} 
※α(平滑定数)=2÷(n+1)

メリットとデメリット

名称 メリット デメリット
単純移動平均線(SMA) 大きなトレンドをつかみやすい 直近の市場の動きからは少々遅れをとる
加重移動平均線(WMA) 緩やかな上昇・下降相場では最も安定する レンジ相場や急な変動では利用価値がほぼなくなる
指数平滑移動平均線(EMA) 直近のトレンド把握にも有効 動きに敏感に反応する分ダマシのサインも多くなる

それぞれメリットデメリットがあるため他の指標と組み合わせたり、期間を変えたり、シグナルを見定めることが何よりも重要です!!

コードを実装してみる

TA-Libを用いる理由

今回(ほぼ毎回ですが)TA-Libを用いています。
あれ..? 移動平均線ってデフォルトの簡単な奴があるじゃん..と思った方。
確かにただ平均をとる単純移動平均線ならTA-Libを使うまでもない(と言うか多分めんどくさい)ですが、計算が厄介指数平滑移動平均線くらいになってくると、自分で計算式を書くのが億劫になってきます。
また、他の指標を使う際に練れてもらうためにも今回TA-Libを使用しています。

SMA

今回の目標は短期、中期、長期の3本の移動線を描画するのがとりあえずゴールなので、細かいトレード法は後日公開ということでとりあえず実装してみます。

https://factory.quantx.io/developer/a6bc02085d7c4a958d8b50c72ddcf696
ここのURLからコードをcloneして使ってください。

参考までにコードも置いときます。

sma.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.6942",
            "jp.stock.2721",
            "jp.stock.9263",
            "jp.stock.6556",
            "jp.stock.3092",
            "jp.stock.4380",
            "jp.stock.3856",
            "jp.stock.2930",
            "jp.stock.2146",
            "jp.stock.3445",
            "jp.stock.6065",
            "jp.stock.8927",
            "jp.stock.2371",
            "jp.stock.3765",
            "jp.stock.3932",
            "jp.stock.5542",
            "jp.stock.3779",
            "jp.stock.2127",
            "jp.stock.2211",
            "jp.stock.8167",
            "jp.stock.3064",
            "jp.stock.3276",
            "jp.stock.8918",
            "jp.stock.2928",
            "jp.stock.6071",
            "jp.stock.1434",
            "jp.stock.3676",
            "jp.stock.3825",
            "jp.stock.6067",
            "jp.stock.1333", 
            "jp.stock.3267",
            "jp.stock.1814", 
            "jp.stock.4521", 
            "jp.stock.4503", 
            "jp.stock.5194", 
            "jp.stock.5391", 
            "jp.stock.5940", 
            "jp.stock.7226", 
            "jp.stock.7956", 
            "jp.stock.3092", 
            "jp.stock.7148", 
            "jp.stock.9115", 
            "jp.stock.9508", 
            "jp.stock.2371", 
            "jp.stock.3765", 
            "jp.stock.6533", 
            "jp.stock.4587", 
            "jp.stock.4536", 
            "jp.stock.3064", 
            "jp.stock.1808", 
          ],
          "columns": [
            "open_price_adj",     # 始値(株式分割調整後)
            "high_price_adj",     # 高値(株式分割調整後)
            "low_price_adj",      # 安値(株式分割調整後)
            "close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    #シグナル定義
    def _my_signal(data):

      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      cp = data["close_price_adj"].fillna(method="ffill")

      #単純移動平均線(SMA)の設定
      #データの入れ物を用意
      s_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      m_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      l_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      #TA-Libによる計算
      for (sym,val) in cp.items():
        s_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=5)
        m_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=25)
        l_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=75)
      #SMAの売買シグナルの定義
      s_sma_ratio = s_sma/m_sma
      l_sma_ratio = m_sma/l_sma
      df_sma_buy_sig = (s_sma_ratio > 1.02) & (s_sma_ratio < 1.04) & (l_sma_ratio > 1.02) & (l_sma_ratio < 1.04)
      df_sma_sell_sig = (s_sma_ratio < 0.96) & (l_sma_ratio < 0.96) 

      #売買シグナルの設定
      buy_sig = df_sma_buy_sig 
      sell_sig = df_sma_sell_sig 

      return {
        "s_sma": s_sma,
        "m_sma": m_sma,
        "l_sma": l_sma,
        "buy:sig":buy_sig,
        "sell:sig":sell_sig, 
        }

     # シグナル登録
    ctx.regist_signal("my_signal", _my_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)
        sec.order_target_percent(0.07, comment= "買いシグナル")

    # 売りシグナル
    df_sell = df[df["sell:sig"]]
    if not df_sell.empty:
      for (sym, val) in df_sell.iterrows(): 
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment= "売りシグナル")

    #利食い 損切り
    # done_syms = set([])
    # for (sym,val) in ctx.portfolio.positions.items():
    #     returns = val["returns"]
    #     #ctx.logger.debug("%s %f" % (sym, returns))
    #     if returns < -0.15:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="損切り(%f)" % returns)
    #       done_syms.add(sym)
    #     elif returns > 0.30:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
    #       done_syms.add(sym)

コード解説

基本設定

【1~3行目】ライブラリーのimport

sma.py
import talib as ta 
import pandas as pd 
import numpy as np 

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

【5~74行目】初期化 (トレードの基本設定)

sma.py
#関数の初期化
def initialize(ctx):
  #設定
    ctx.logger.debug("initialize() called")
    ctx.configure(
      target="jp.stock.daily",
      channels={          #銘柄選択
        "jp.stock": {
          "symbols": [
            "jp.stock.6942",
            "jp.stock.2721",
            "jp.stock.9263",
            "jp.stock.6556",
            "jp.stock.3092",
            "jp.stock.4380",
            "jp.stock.3856",
            "jp.stock.2930",
            "jp.stock.2146",
            "jp.stock.3445",
            "jp.stock.6065",
            "jp.stock.8927",
            "jp.stock.2371",
            "jp.stock.3765",
            "jp.stock.3932",
            "jp.stock.5542",
            "jp.stock.3779",
            "jp.stock.2127",
            "jp.stock.2211",
            "jp.stock.8167",
            "jp.stock.3064",
            "jp.stock.3276",
            "jp.stock.8918",
            "jp.stock.2928",
            "jp.stock.6071",
            "jp.stock.1434",
            "jp.stock.3676",
            "jp.stock.3825",
            "jp.stock.6067",
            "jp.stock.1333", 
            "jp.stock.3267",
            "jp.stock.1814", 
            "jp.stock.4521", 
            "jp.stock.4503", 
            "jp.stock.5194", 
            "jp.stock.5391", 
            "jp.stock.5940", 
            "jp.stock.7226", 
            "jp.stock.7956", 
            "jp.stock.3092", 
            "jp.stock.7148", 
            "jp.stock.9115", 
            "jp.stock.9508", 
            "jp.stock.2371", 
            "jp.stock.3765", 
            "jp.stock.6533", 
            "jp.stock.4587", 
            "jp.stock.4536", 
            "jp.stock.3064", 
            "jp.stock.1808", 
          ],
          "columns": [
            "open_price_adj",    # 始値(株式分割調整後)
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

初期化では、アルゴリズムで利用する市場(日本株等)、トレードする銘柄、利用する値(終値、高値など)を設定します。
6行目で初期化用の関数を定義
8行目でプログラムのログ出力を行うコード(バックテストを行うときに必要)
9行目以下にトレードの基本設定を行います。
10行目のtarget="jp.stock.daily"で日足の日本株のデータを使うことを宣言します。
11行目のchannels以下で実際にデータを入れていきます。
13行目で"symbols"と書かれてありますが,{}に銘柄のデータを入れます。
14~63行目まで"jp.stock."銘柄番号"" で使用する銘柄のデータを入れることができます。
データがない企業もありますので、バックテスト後エラーが起きた場合はここを見るといいと思います。
65行目の"columns"と書かれてありますが,{}に必要なデータ(終値など)を入れます。
トムソン・ロイター社からデータをいただいているセンチメントデータなども使えます。

シグナル定義

【76~80行目】使用するデータ量の設定

sma.py
    #シグナル定義
    def _my_signal(data):

      #各銘柄の終値(株式分割調整後)を取得、欠損データの補完 
      cp = data["close_price_adj"].fillna(method="ffill")

77行目では売買シグナルを生成する関数の定義しています。
80行目では各銘柄の終値(株式分割調整後)のデータを取得します。今回、単純移動平均線では必要なデータが終値(株式分割調整後)だけだったのでcpとして定義しました。データではたまに欠損値(値がNaNとなり、計算できない値)が含まれる場合があります。欠損値があると計算ができません。
そこで、fillna(method='ffill')を使うとNaNがあった場合に、さまざまな方法で自動的に補完をしてくれるようになります。

【82~86行目】データの容れ物を用意

sma.py
      #単純移動平均線(SMA)の設定
      #データの容れ物を用意
      s_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      m_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      l_sma = pd.DataFrame(data=0,columns=[], index=cp.index)

今回短期(5日)、中期(25日)、長期(75日)の三本の単純移動平均を計算します。
そのデータを格納するための容れ物をDataFrameというオブジェクトを用い、作ります。
・短期をs_sma
・中期をm_sma
・長期をl_sma
と今回はしています。

【87~91行目】TA-Libによる計算

sma.py
     #TA-Libによる計算
      for (sym,val) in cp.items():
        s_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=5)
        m_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=25)
        l_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=75)

配列の際データがうまく使えるように.values.astype(np.double)というメソッドを用いたコードを記述しています。別のデータを入れる場合にもこのメソッドは同様につけてください。(つけないと多分エラーが出ます)
TA-Libのドキュメントで単純移動平均線は終値と期間が必要だったので記述します。
すると計算結果が返り値として出てきます。
TA-Lib Documentation

【92~96行目】SMAの売買シグナルの定義

sma.py
      #SMAの売買シグナルの定義
      s_sma_ratio = s_sma/m_sma
      l_sma_ratio = m_sma/l_sma
      df_sma_buy_sig = (s_sma_ratio > 1.02) & (s_sma_ratio < 1.04) & (l_sma_ratio > 1.02) & (l_sma_ratio < 1.04)
      df_sma_sell_sig = (s_sma_ratio < 0.96) & (l_sma_ratio < 0.96)    

SMAの売買シグナル部分を定義していきましょう。
今回は簡単にsampleを応用したものを作ってみます。
短期線を長期線の比率を出したのものを二つ用意し、SMAのシグナルを定義します。
数値を変えると結果も大きく変わります!!

【98~100行目】全体の売買シグナルの定義

sma.py
      #売買シグナルの設定
      buy_sig = df_sma_buy_sig 
      sell_sig = df_sma_sell_sig 

他の指標とかけ合わせてみたい場合はここで設定します。(個人的に見やすいと思ってるだけです。)
あんまり今回はあまり意味ないですが、SMAのシグナルとイコールで結んでいます。

【98~100行目】移動平均線と売買シグナルの可視化

sma.py
      return {
        "s_sma": s_sma,
        "m_sma": m_sma,
        "l_sma": l_sma,
        "buy:sig":buy_sig,
        "sell:sig":sell_sig, 
        }

return内にシグナル定義部分で定義した変数を入れ、バックテスト後可視化できるようにしましょう。

【110~111行目】移動平均線と売買シグナルの可視化

sma.py
     # シグナル登録
    ctx.regist_signal("my_signal", _my_signal)

シグナル登録し、シグナルは生成されました!!

ポジション設定

【113~142行目】取引の数量設定

sma.py
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)
        sec.order_target_percent(0.07, comment= "買いシグナル")

    # 売りシグナル
    df_sell = df[df["sell:sig"]]
    if not df_sell.empty:
      for (sym, val) in df_sell.iterrows(): 
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment= "売りシグナル")

    # 利食い 損切り
    # done_syms = set([])
    # for (sym,val) in ctx.portfolio.positions.items():
    #     returns = val["returns"]
    #     #ctx.logger.debug("%s %f" % (sym, returns))
    #     if returns < -0.15:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="損切り(%f)" % returns)
    #       done_syms.add(sym)
    #     elif returns > 0.30:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
    #       done_syms.add(sym)

実際シグナルが出たときにどのくらいの銘柄を売買するか等の調整を行います。
今回はorder_target_percentというメソッドを用い、買いシグナルが出た際、総資産の7%の買いを入れ、売りシグナルが出たら全て売るという取引を行なっています。
130行目から142行目までは損切りや利益確定売りの調節ができます。(今回はコメントアウトを用い無効化してます。)

コードの解説よくわからなかったという方はコチラの記事にテンプレート構文のわかりやすい解説が乗っているので参考にしてみてください!
https://qiita.com/RS4322/items/bef8bdfb49fdffeb85d2

結果

スクリーンショット 2019-01-08 23.25.57.png

銘柄選別がよかったか、損益率はそこそこですが、MaxDrawdownが大きいですね。
単純移動平均線はただ使うとダマシが多いです。
グランビルの法則、パーフェクトオーダー等、よく使われるエントリー方法を実装するのが今後の課題です。
スクリーンショット 2019-01-08 23.29.24.png
移動平均線は3本ちゃんと描画されています!!

番外編 WMAとEMAの実装

紹介したWMAとEMAも簡単に実装できます。

https://factory.quantx.io/developer/8b28975e529247c0a25f9fd61edc0cb0
このURLからcloneしてください。

sma-wma-ema.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.6942",
            "jp.stock.2721",
            "jp.stock.9263",
            "jp.stock.6556",
            "jp.stock.3092",
            "jp.stock.4380",
            "jp.stock.3856",
            "jp.stock.2930",
            "jp.stock.2146",
            "jp.stock.3445",
            "jp.stock.6065",
            "jp.stock.8927",
            "jp.stock.2371",
            "jp.stock.3765",
            "jp.stock.3932",
            "jp.stock.5542",
            "jp.stock.3779",
            "jp.stock.2127",
            "jp.stock.2211",
            "jp.stock.8167",
            "jp.stock.3064",
            "jp.stock.3276",
            "jp.stock.8918",
            "jp.stock.2928",
            "jp.stock.6071",
            "jp.stock.1434",
            "jp.stock.3676",
            "jp.stock.3825",
            "jp.stock.6067",
            "jp.stock.1333", 
            "jp.stock.3267",
            "jp.stock.1814", 
            "jp.stock.4521", 
            "jp.stock.4503", 
            "jp.stock.5194", 
            "jp.stock.5391", 
            "jp.stock.5940", 
            "jp.stock.7226", 
            "jp.stock.7956", 
            "jp.stock.3092", 
            "jp.stock.7148", 
            "jp.stock.9115", 
            "jp.stock.9508", 
            "jp.stock.2371", 
            "jp.stock.3765", 
            "jp.stock.6533", 
            "jp.stock.4587", 
            "jp.stock.4536", 
            "jp.stock.3064", 
            "jp.stock.1808", 
          ],
          "columns": [
            "open_price_adj",    # 始値(株式分割調整後)
            "high_price_adj",    # 高値(株式分割調整後)
            "low_price_adj",     # 安値(株式分割調整後)
            "close_price",        # 終値
            "close_price_adj",    # 終値(株式分割調整後) 
          ] 
        }
      }
    )

    def _my_signal(data):
      cp = data["close_price_adj"].fillna(method="ffill")

      #単純移動平均線(SMA)の設定
      s_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      m_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      l_sma = pd.DataFrame(data=0,columns=[], index=cp.index)
      for (sym,val) in cp.items():
        s_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=5)
        m_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=25)
        l_sma[sym] = ta.SMA(cp[sym].values.astype(np.double), timeperiod=75)
      s_sma_ratio = s_sma/m_sma
      l_sma_ratio = m_sma/l_sma
      df_sma_buy_sig = (s_sma_ratio > 1.02) & (s_sma_ratio < 1.05) & (l_sma_ratio > 1.02) & (l_sma_ratio < 1.05)
      df_sma_sell_sig = (s_sma_ratio < 0.95) & (l_sma_ratio < 0.95) 

       #加重移動平均線(WMA)の設定
      s_wma = pd.DataFrame(data=0,columns=[], index=cp.index)
      m_wma = pd.DataFrame(data=0,columns=[], index=cp.index)
      l_wma = pd.DataFrame(data=0,columns=[], index=cp.index)
      for (sym,val) in cp.items():
        s_wma[sym] = ta.WMA(cp[sym].values.astype(np.double), timeperiod=5)
        m_wma[sym] = ta.WMA(cp[sym].values.astype(np.double), timeperiod=25)
        l_wma[sym] = ta.WMA(cp[sym].values.astype(np.double), timeperiod=75)
      s_wma_ratio = s_wma/m_wma
      l_wma_ratio = m_wma/l_wma
      df_wma_buy_sig = (s_wma_ratio > 1.02) & (s_wma_ratio < 1.05) & (l_wma_ratio > 1.02) & (l_wma_ratio < 1.05)
      df_wma_sell_sig = (s_wma_ratio < 0.95) & (l_wma_ratio < 0.95) 

       #指数平滑移動平均線(EMA)の設定
      s_ema = pd.DataFrame(data=0,columns=[], index=cp.index)
      m_ema = pd.DataFrame(data=0,columns=[], index=cp.index)
      l_ema = pd.DataFrame(data=0,columns=[], index=cp.index)
      for (sym,val) in cp.items():
        s_ema[sym] = ta.EMA(cp[sym].values.astype(np.double), timeperiod=5)
        m_ema[sym] = ta.EMA(cp[sym].values.astype(np.double), timeperiod=25)
        l_ema[sym] = ta.EMA(cp[sym].values.astype(np.double), timeperiod=75)
      s_ema_ratio = s_ema/m_ema
      l_ema_ratio = m_ema/l_ema
      df_ema_buy_sig = (s_ema_ratio > 1.02) & (s_ema_ratio < 1.05) & (l_ema_ratio > 1.02) & (l_ema_ratio < 1.05)
      df_ema_sell_sig = (s_ema_ratio < 0.95) & (l_ema_ratio < 0.95) 

      #売買シグナルの設定
      buy_sig = df_sma_buy_sig & df_wma_buy_sig & df_ema_buy_sig
      sell_sig = df_sma_sell_sig & df_wma_sell_sig & df_ema_sell_sig


      return {
        "s_sma": s_sma,
        "m_sma": m_sma,
        "l_sma": l_sma,
        "s_wma": s_wma,
        "m_wma": m_wma,
        "l_wma": l_wma,
        "s_ema": s_ema,
        "m_ema": m_ema,
        "l_ema": l_ema,
        "buy:sig":buy_sig,
        "sell:sig":sell_sig, 
        }


    # シグナル登録 memo 参照
    ctx.regist_signal("my_signal", _my_signal)


 # シグナル登録
    ctx.regist_signal("my_signal", _my_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)
        sec.order_target_percent(0.07, comment= "買いシグナル")

    # 売りシグナル
    df_sell = df[df["sell:sig"]]
    if not df_sell.empty:
      for (sym, val) in df_sell.iterrows(): 
        sec = ctx.getSecurity(sym)
        sec.order_target_percent(0, comment= "売りシグナル")

    #利食い 損切り
    # done_syms = set([])
    # for (sym,val) in ctx.portfolio.positions.items():
    #     returns = val["returns"]
    #     #ctx.logger.debug("%s %f" % (sym, returns))
    #     if returns < -0.15:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="損切り(%f)" % returns)
    #       done_syms.add(sym)
    #     elif returns > 0.30:
    #       sec = ctx.getSecurity(sym)
    #       sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
    #       done_syms.add(sym)

先ほど説明したTA-Libライブラリーの計算部分をta.WMAやta.EMAにすると簡単にWMAやEMAが計算できます!!
やばそうだけどまとめて載せてみました。

結果

スクリーンショット 2019-01-08 23.42.01.png
ドローダウンがひどすぎる気が、、
スクリーンショット 2019-01-08 23.42.13.png
9本の移動平均線がちゃんと描画されていますね。

終わりに

移動平均線はトレード方法が複数あるので次回はグランビルの法則とかパーフェクトオーダー等の実装をしていきます!!

宣伝

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

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

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

免責注意事項

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

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4