noteのタイトル画像

[Puppeteer] ta-libを使わずにpandasでSMA,EMAを計算させる

先日紹介した「Puppeteer(傀儡師)」でローソク足を取得できるように拡張したので、そのローソク足(ohlcv)データからSMA(単純移動平均)とEMA(指数平滑移動平均)を出力してみたいと思います。

javascriptでガリガリとコードを書いていたときはTa-Libという外部ライブラリを使っていました。
pythonでもta-libはありますが、ta-libのインストールが意外と面倒なので、さくっとpythonモジュールである「pandas」を召喚して計算してみることにします。

Puppeteer本体はこちらから導入してください。

Puppeteerが導入できたら、puppetsフォルダの下に「ma」というフォルダを作成しましょう。
そしてmaフォルダの下に以下の2つのファイルを作成します。

- puppets
  - ma
    - ma.py
    - ma.json

ma.py

# -*- coding: utf-8 -*-
# ==========================================
# サンプル・ストラテジ
# ==========================================
from datetime import datetime
import pandas as pd
from collections import OrderedDict

from puppeteer import Puppeteer

# ==========================================
# Puppet(傀儡) クラス
#   param:
#       puppeteer: Puppeteerオブジェクト
# ==========================================
class Puppet(Puppeteer):
    _exchange = None    # 取引所オブジェクト(ccxt.bitmex)
    _logger = None      # logger
    _config = None      # 定義ファイル

    # ==========================================================
    # 初期化
    #   param:
    #       puppeteer: Puppeteerオブジェクト
    # ==========================================================
    def __init__(self, Puppeteer):
        self._exchange = Puppeteer._exchange
        self._logger = Puppeteer._logger
        self._config = Puppeteer._config
        
    # ==========================================================
    # 売買実行
    #   param:
    #       ticker: Tick情報
    #       orderbook: 板情報
    #       position: ポジション情報
    #       balance: 資産情報
    #       candle: ローソク足
    # ==========================================================
    def run(self, ticker, orderbook, position, balance, candle):
        # --------------------------
        # ここに処理を記述します
        # --------------------------

        # ------------------------------------------------------
        # candle取得
        # ------------------------------------------------------

        # ------------------------------------------------------
        # Pandasのデータフレームに
        # ------------------------------------------------------
        df_ohlcv = pd.DataFrame(candle,
                  columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
        
        # ------------------------------------------------------
        # 日時データをDataFrameのインデックスにする
        # ------------------------------------------------------
        df_ohlcv = df_ohlcv.set_index('timestamp')
        
        # ------------------------------------------------------
        # SMA5, SMA14, SMA21を計算する
        #  参考にしたサイト: https://note.nkmk.me/python-pandas-rolling/
        # ------------------------------------------------------
        df_sma = pd.DataFrame(OrderedDict({
            'SMA5' : df_ohlcv['close'].rolling(
                    window=5,           # indexを遡って計算対象とする要素数を決める
                    min_periods=5,      # 有効な計算結果を出すのに最低限必要な要素数を指定する
                    center=False        # center=Trueとすると、起点とするindexとその前後あわせてwindow個の要素を計算対象とする
                ).mean(),               # 平均を取る
            'SMA14' : df_ohlcv['close'].rolling(window=14).mean(),  # これでもOK
            'SMA21' : df_ohlcv['close'].rolling(window=21).mean(),  # これでもOK
        }))
        print(df_sma)

        # ------------------------------------------------------
        # EMA5, EMA14, EMA21を計算する
        #  参考にしたサイト: https://teratail.com/questions/120255
        # ------------------------------------------------------
        df_ema = pd.DataFrame(OrderedDict({
            'EMA5' : df_ohlcv['close'].ewm(
                    span=5,             # ewmの範囲
                ).mean(),               # 平均を取る
            'EMA14' : df_ohlcv['close'].ewm(span=14).mean(),
            'EMA21' : df_ohlcv['close'].ewm(span=21).mean(),
        }))
        print(df_ema)

ma.json

{
    "//" : "===============================================",
    "//" : " システムで利用",
    "//" : "===============================================",
    "//" : "取引所のapiKey, secretを設定します",
    "APIKEY" : "YOUR_APIKEY",
    "SECRET" : "YOUR_SECRET",

    "//" : "bitmex取引所で対応する通貨ペア等を記述",
    "SYMBOL" : "BTC/USD",
    "INFO_SYMBOL" : "XBTUSD",
    "COIN_BASE" : "BTC",
    "COIN_QUOTE" : "USD",
    "//" : "bitmex取引所の価格の最小幅(0.5ドル)",
    "PRICE_UNIT" : 0.5,

    "//" : "TestNetを使うか?(使う: true, 使わない: false)",
    "USE_TESTNET" : true,

    "//" : "ticker, orderbook, position, balance, candle のどれを利用するかを指定する。Falseを指定した場合はそのデータは取得しない",
    "USE" : {
        "TICKER" : false,
        "ORDERBOOK" : false,
        "POSITION" : false,
        "BALANCE" : false,
        "CANDLE" : true
    },

    "//" : "ローソク足の収集定義。",
    "CANDLE" : {
        "//" : "ローソク足の足幅を設定する。設定値= 1m, 5m, 1h, 1d",
        "TIMEFRAME" : "1m",
        "//" : "データ取得開始時刻(UNIXTIME:1ミリ秒)、使用しない場合 もしくは自動の場合は null(None) を指定",
        "SINCE" : null,
        "//" : "取得件数(未指定:100、MAX:500)",
        "LIMIT" : null,
        "//" : "True(New->Old)、False(Old->New) 未指定時はFlase",
        "REVERSE" : false,
        "//" : "True(最新の未確定足を含む)、False(含まない) 未指定はTrue",
        "PARTIAL" : false
    },

    "//" : "板情報の収集定義。",
    "ORDERBOOK" : {
        "//" : "取得件数(未指定:25、MAX:取引所による?)",
        "LIMIT" : null
    },

    "//" : "インターバルを秒で設定",
    "INTERVAL" : 30,

    "//" : "discord通知用URL",
    "DISCORD_WEBHOOK_URL" : "",

    "//" : "===============================================",
    "//" : " ユーザで自由に定義",
    "//" : "===============================================",
    "//" : "売買するサイズ",
    "LOT_SIZE" :50
}

とりあえず、TestNetのローソク足を取得して、SMA,EMAを出力させてみましょう。

コンソールで「puppeteer」フォルダに移動し、そこで

python3 puppeteer.py puppets/ma/ma.py puppets/ma/ma.json

のコマンドを実行します。

すると以下のようなSMAが出力され、

                 SMA5        SMA14        SMA21
timestamp                                      
1555207740000     NaN          NaN          NaN
1555207800000     NaN          NaN          NaN
1555207860000     NaN          NaN          NaN
1555207920000     NaN          NaN          NaN
1555207980000  5049.8          NaN          NaN
1555208040000  5050.0          NaN          NaN
1555208100000  5050.0          NaN          NaN
1555208160000  5050.0          NaN          NaN
1555208220000  5050.1          NaN          NaN
1555208280000  5050.1          NaN          NaN
1555208340000  5050.1          NaN          NaN
1555208400000  5050.1          NaN          NaN
1555208460000  5050.1          NaN          NaN
1555208520000  5050.0  5049.964286          NaN
1555208580000  5050.1  5050.071429          NaN
1555208640000  5053.1  5051.142857          NaN
1555208700000  5056.1  5052.214286          NaN
1555208760000  5061.8  5054.250000          NaN
1555208820000  5067.4  5056.250000          NaN
1555208880000  5073.1  5058.321429          NaN
1555208940000  5075.9  5060.392857  5056.880952
1555209000000  5078.8  5062.500000  5058.333333
1555209060000  5078.9  5064.535714  5059.714286
1555209120000  5079.1  5066.607143  5061.095238
1555209180000  5079.1  5068.678571  5062.476190
1555209240000  5076.8  5069.928571  5063.309524
1555209300000  5074.2  5071.107143  5064.095238
1555209360000  5071.9  5072.357143  5064.928571
1555209420000  5066.7  5072.535714  5065.071429
1555209480000  5061.5  5071.678571  5065.190476
...               ...          ...          ...
1555211940000  5026.6  5026.964286  5027.642857
1555212000000  5026.8  5026.892857  5027.523810
1555212060000  5027.0  5026.857143  5027.380952
1555212120000  5027.3  5026.821429  5027.261905
1555212180000  5027.3  5026.750000  5027.190476
1555212240000  5027.5  5026.857143  5027.142857
1555212300000  5027.5  5026.928571  5027.119048
1555212360000  5027.5  5027.000000  5027.142857
1555212420000  5027.6  5027.107143  5027.119048
1555212480000  5027.8  5027.250000  5027.119048
1555212540000  5027.9  5027.392857  5027.142857
1555212600000  5028.1  5027.535714  5027.166667
1555212660000  5028.2  5027.678571  5027.238095
1555212720000  5028.2  5027.750000  5027.309524
1555212780000  5028.2  5027.821429  5027.380952
1555212840000  5028.2  5027.892857  5027.476190
1555212900000  5028.4  5028.035714  5027.642857
1555212960000  5028.7  5028.178571  5027.785714
1555213020000  5029.0  5028.357143  5027.928571
1555213080000  5029.3  5028.464286  5028.095238
1555213140000  5029.7  5028.678571  5028.261905
1555213200000  5029.8  5028.857143  5028.404762
1555213260000  5029.9  5029.000000  5028.523810
1555213320000  5030.0  5029.142857  5028.642857
1555213380000  5030.2  5029.285714  5028.785714
1555213440000  5030.2  5029.428571  5028.952381
1555213500000  5030.2  5029.571429  5029.047619
1555213560000  5030.2  5029.714286  5029.166667
1555213620000  5030.3  5029.892857  5029.309524
1555213680000  5030.2  5030.000000  5029.404762

[100 rows x 3 columns]

つぎにすぐ、EMAが出力されます。

                      EMA5        EMA14        EMA21
timestamp                                           
1555207860000  5050.000000  5050.000000  5050.000000
1555207920000  5050.000000  5050.000000  5050.000000
1555207980000  5050.000000  5050.000000  5050.000000
1555208040000  5050.000000  5050.000000  5050.000000
1555208100000  5050.000000  5050.000000  5050.000000
1555208160000  5050.000000  5050.000000  5050.000000
1555208220000  5050.177028  5050.105361  5050.093366
1555208280000  5050.115623  5050.084754  5050.077456
1555208340000  5050.076052  5050.069149  5050.065229
1555208400000  5050.050254  5050.057032  5050.055579
1555208460000  5050.033307  5050.047440  5050.047799
1555208520000  5050.022118  5050.039731  5050.041422
1555208580000  5050.182235  5050.112411  5050.100111
1555208640000  5055.138467  5052.406889  5051.938842
1555208700000  5058.433169  5054.308219  5053.499932
1555208760000  5065.132312  5057.897393  5056.404863
1555208820000  5069.425899  5060.835721  5058.852263
1555208880000  5072.619427  5063.457089  5061.085552
1555208940000  5074.747244  5065.675792  5063.032476
1555209000000  5076.331973  5067.630752  5064.790902
1555209060000  5077.221494  5069.225652  5066.284464
1555209120000  5077.814408  5070.587354  5067.602315
1555209180000  5078.209641  5071.752385  5068.768731
1555209240000  5074.639548  5071.166509  5068.640359
1555209300000  5071.926258  5070.526421  5068.425996
1555209360000  5070.450800  5070.112883  5068.334104
1555209420000  5064.633764  5067.782246  5066.824982
1555209480000  5060.755797  5065.774761  5065.474520
1555209540000  5057.337171  5063.705503  5064.021610
1555209600000  5054.724767  5061.785198  5062.621208
...                    ...          ...          ...
1555212060000  5027.147656  5027.036018  5027.704957
1555212120000  5027.265104  5027.097884  5027.686305
1555212180000  5027.176736  5027.084833  5027.623854
1555212240000  5027.451157  5027.206858  5027.658079
1555212300000  5027.467438  5027.245944  5027.643697
1555212360000  5027.478292  5027.279819  5027.630624
1555212420000  5027.652195  5027.375845  5027.664226
1555212480000  5027.768130  5027.459067  5027.694769
1555212540000  5028.012087  5027.597860  5027.768011
1555212600000  5028.174724  5027.718146  5027.834588
1555212660000  5028.116483  5027.755727  5027.849632
1555212720000  5028.077655  5027.788297  5027.863307
1555212780000  5028.051770  5027.816524  5027.875738
1555212840000  5028.201180  5027.907655  5027.932508
1555212900000  5028.634120  5028.119969  5028.075051
1555212960000  5028.922747  5028.303974  5028.204627
1555213020000  5029.115164  5028.463445  5028.322418
1555213080000  5029.243443  5028.601652  5028.429495
1555213140000  5029.662295  5028.854766  5028.617762
1555213200000  5029.774864  5029.007464  5028.743444
1555213260000  5029.849909  5029.139803  5028.857696
1555213320000  5029.899939  5029.254496  5028.961558
1555213380000  5030.099960  5029.420563  5029.101436
1555213440000  5030.233306  5029.564489  5029.228594
1555213500000  5030.155538  5029.622557  5029.298730
1555213560000  5030.103692  5029.672883  5029.362489
1555213620000  5030.235794  5029.783165  5029.465909
1555213680000  5030.157196  5029.812076  5029.514467
1555213740000  5030.104798  5029.837133  5029.558610
1555213800000  5030.236532  5029.925515  5029.644197

[100 rows x 3 columns]

このような感じです。

pandasを使うとあっけなくSMAやEMAが計算できてしまって、少々拍子抜けしてしまいました。
pandasはデータ処理の基本ツールです。
詳しい使い方などは多くの方が紹介されているのでここではあえてしませんが、ここなどで勉強されると良いと思います。

楽しいbotライフを!

ソフトウェア・エンジニアを40年以上やってます。 「Botを作りたいけど敷居が高い」と思われている方にも「わかる」「できる」を感じてもらえるように頑張ります。 よろしくお願い致します。