10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Google Colaboratory上で行うQuantX-SDK事始め 

Last updated at Posted at 2019-03-20

自己紹介

株式会社Smart Tradeでインターンをしているkatakyoです。
日本株のテクニカル分析法の統計データを取って欲しいと言われ、その際QuantX-SDKを使用して欲しいと言われたので、使用方法を記述しておきます。
テンプレのGoogle Colaboratoryを作成したので、コピーして、アクセスキーを入れて使ってみてください。

#QunatX SDKに関して
コードをテンプレ化したり、バックテストの細かい調整もできるそうです。
より細かい統計分析なんかも行えます。

今回やること

  • Google Colaboratoryの導入
  • QuantX-SDKの導入からバックテスト方法まで

Google Colaboratoryの準備

https://colab.research.google.com/
上記のサイトに飛んで、こんにちはColaboratoryを選択
スクリーンショット_2019-03-13_10_42_11.png
すると自分のGoogleドライブの中にファイルがコピーされます。

#新規ファイルの作り方
新規or右クリックをしてその他をクリックするとColaboratorの新規ファイルが作れます。
スクリーンショット_2019-03-13_10_46_35.png

#QunatX SDKの準備
##下準備

  • quantx-sdkのインストール
  • アクセスキーの取得

###quantx-sdkのインストール
コチラをコピーして実行

注)simplejsonをinstallしないと動かなくなったので追記しました。

!pip install quantx_sdk
!pip install simplejson

実行するとquantx-sdkのインストールされます

###アクセスキーの取得
アクセスキーを取得
sdk を使うためには,アクセスキーとシークレットキーが必要です

アクセスキーとシークレットキーは、quantxにログインしてhttps://factory.quantx.io/settings/token から取得してください
スクリーンショット_2019-03-13_11_07_00.png

取得したアクセスキーとシークレットキーを''内に貼り付けてください

public_key = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
secret_key = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

##新規プロジェクトの作成

# sdk をインポート
from quantx_sdk import QX

# 新規プロジェクト作成
qx = QX(access_key, secret_key)

# 新規プロジェクト名。5文字以上の適当な文字列
new_name = "an new project"

# 新規プロジェクトを作成。
prj = qx.new_project(new_name)

コレを貼り付けて実行すると、上記を実行した後
https://factory.quantx.io/projects
にログインすると
new_nameの名前を持つ新しいプロジェクトが作成されます

スクリーンショット_2019-03-13_11_17_34.png

"an new project"を変えて、わかりやすいプロジェクト名にしましょう。

#ハッシュ番号(プロジェクトID)
先ほどの新規プロジェクト作成セルを再度実行すると同じ名前のプロジェクトが複数作られます。

QuantXではプロジェクトの管理をハッシュ番号で行っているので、プロジェクト名は固有である必要はありません。(同じ名前のプロジェクト名でも上書き保存とかされません)
つまりひとつのプロジェクトを使いまわしたい場合は,このハッシュ番号を使ってプロジェクトを指定することになります。

ハッシュ番号はプロジェクトのURLの developer 以下の文字列と同じになります
例: https://factory.quantx.io/developer/xxxxxxxxxxxxxxxxxxxxxxxxxxxx

#プロジェクト関係
##プロジェクト一覧の取得
以下のコードを記述
左の変数の名前はなんでも大丈夫です。
ただし、後で変数の名前間違えるとエラー吐くので注意です。

# project
projects = qx.projects()

##ソースの取得
以下のコードを記述

source = projects[0].source() 
print(source)

実行すると、QuantX上に保存されているプロジェクトの一番上のPythonコードが出て来ます。
[]の文字を0から1に変えると2番目のプロジェクトが記述されます。

ハッシュ番号の取得

上記の方法でもプロジェクト取得ができますが、プロジェクト数が多くなるほど、取得が面倒になるのでハッシュ番号でのプロジェクト取得をお勧めします!!

## ハッシュ番号を格納,確認.
prjct_hash = projects[0].project_hash
prjct_hash

上記のコードを入れると、一番上のプロジェクトのハッシュ番号が取得できます。

スクリーンショット_2019-03-20_11_23_35.png

URLから取得もできます。

ハッシュ番号からプロジェクトの取得

# ハッシュ番号を入力
prjct_hash = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# ハッシュ番号によるプロジェクトの取得
p = qx.project(prjct_hash)
#ソースコードの取得
p_source = p.source()
#ソースコードの表示
print(p_source)

prjct_hashのxxxxx‥の部分に取得したいプロジェクトのハッシュ番号を入力してください。
セルを実行するとソースコードが表示されると思います。

バックテストパラメーターの取得

#バックテストパラメーターの取得
p.current_backtest_params()

先ほどハッシュ番号で取得したバックテストのパラメーターを表示します.
何も設定しないとデフォルトの状態のままバックテストが実行されます。

バックテストの実行

# バックテストパラメータ
# バックテストパラメータ
bt_parameter = {
    'engine': 'maron-0.0.5',
    'from_date': '2019-01-01',
    'to_date': '2019-12-31',
    'capital_base': 10000000}

# backtest の実行. 
bt = p.backtest(bt_parameter)

## backtest result インスタンスを作成
join = bt.join()

## 結果のサマリーを取得
summary = join.summary()
summary

セルを実行すると、バックテスト結果が返ってきます。
bt_parameterの{}内のパラメータのengineをいじるとバックテストエンジンの変更
from_dateをいじるとバックテストの開始日、to_dateをいじるとバックテストの終了期間を設定することができます。
capital_baseは初期投資額の設定ができます。

その下では,backtest() でバックテストを実行し,バックテストオブジェクトを取得し、
そのオブジェクトにたいして join() を実行して結果を取得します。
summary() で結果のサマリーを取得します.

{'2017': 0.26763600189209225,
 '2018': -0.07424848004177342,
 'Alpha': 0.07543687223665736,
 'Beta': [0.8537311078203127],
 'MaxDrawdown': -0.2030640214563464,
 'ReturnRatio': '17.4',
 'ReturnValue': 11735159.555053711,
 'SharpeRatio': 0.5817548250320305,
 'SignalCount': 656,
 'TradingDays': 492,
 'Volatility': 0.1643756946838794}

セルを実行するとこのような形が出れば大丈夫です。

銘柄毎のバックテストの表示

このままだと各銘柄のリターンがどれだけ違ったか?などの差がわからないので、各銘柄ごとのバックテスト結果も表示してみましょう。

## 銘柄ごとのサマリーの表示
join.symbol_summary()

実行すると

symbol name sector txn_count position_count valuation return
0 jp.stock.2267 (株)ヤクルト本社 食料品 26.0 0.0 0.000000e+00 385000.000000
1 jp.stock.2914 JT 食料品 26.0 0.0 0.000000e+00 -2900.000000
2 jp.stock.3064 (株)MonotaRO 小売業 10.0 0.0 0.000000e+00 115500.000000

このような実行結果が返ってきます。

ソースコードの書き換え

セル内でソースコードを記述し、QuantX上のソースコードを書き換えることができます。
アルゴリズムは文字列で渡します.Python では,ダブルクォーテーション3つでくくると複数行に渡る文字列を記述する事が出来ます。


#簡単なバックテストコード
source = """

import numpy as np 
import talib as ta 


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 _RSI(data):

      df_close = data["close_price_adj"].fillna(method='ffill')
      # memo 参照
      df_rsi = df_close.apply(lambda s: ta.RSI(s.values.astype(np.double), timeperiod=ctx.period),axis=0)

      buy_sig = df_rsi < 30.0 
      sell_sig = df_rsi > 70.0 

      return {
        "rsi": df_rsi,
        "buy:sig": buy_sig, 
        "sell:sig": sell_sig, 

        }

    # シグナル登録
    ctx.regist_signal("RSI", _RSI)

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)
        

"""

次にプロジェクトを指定して,コードをUploadします。
先ほど作った prjct_hash を利用して,プロジェクトオブジェクトを作ります。
そのオブジェクトに対して, upload_source() メソッドでコードをUploadします。
'code': 200 が返ってくればOKです。

# hash番号を与えてプロジェクトオブジェクトを作ります
p = qx.project(prjct_hash)

# プロジェクトにコードをUpload
p.upload_source(source)

上記のセルを実行すると、指定のハッシュ番号のプロジェクトが書き換わっているはずです。
次にバックテストを実行します.上記の通り prj.backtest() すれば良いのですが,プロジェクトパラメータを変更してみましょう。

##変更後のプロジェクトのバックテスト
上で行ったバックテストコードと同じです。アップロードされて入れば上のセルで実行しても同じ結果が出ます。

# バックテストパラメータ
bt_parameter = {
    'engine': 'maron-0.0.5',
    'from_date': '2019-01-01',
    'to_date': '2019-12-31',
    'capital_base': 10000000}


# backtest の実行. 
bt = p.backtest(bt_parameter)

## backtest result インスタンスを作成
join = bt.join()

## 結果のサマリーを取得
summary = join.summary()
summary

銘柄毎のバックテスト

## 銘柄ごとのサマリーの表示.
join.symbol_summary()

アルゴリズムのテンプレ化

アルゴリズム自体は変えずに銘柄だけ変更したという時に、銘柄以外のコードを固定して銘柄だけ動的に変えるということができます。

source をテンプレート化して,銘柄を動的に変えて評価していきましょう。
ctx.codes = [1605, 1925, 2503, 4519, 4911, 6301, 6752, 7741, 8001] で指定している銘柄を動的に変更していきます.

テンプレートで動的に変更したい箇所を {{ 引数名 }} と記述し,レンダーして使います。

my_template = """

import numpy as np 
import talib as ta 


def initialize(ctx):
    # 設定
    ctx.target = 0.10
    ctx.period = 5
    ctx.codes = {{symbols}} # <= 動的に銘柄を変更する
    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 _RSI(data):

      df_close = data["close_price_adj"].fillna(method='ffill')
      # memo 参照
      df_rsi = df_close.apply(lambda s: ta.RSI(s.values.astype(np.double), timeperiod=ctx.period),axis=0)

      buy_sig = df_rsi < 30.0 
      sell_sig = df_rsi > 70.0 

      return {
        "rsi": df_rsi,
        "buy:sig": buy_sig, 
        "sell:sig": sell_sig, 

        }

    # シグナル登録
    ctx.regist_signal("RSI", _RSI)

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)
        
"""

次に銘柄リストを作り,テンプレートにレンダーします
下のセルを実行するとテンプレ化したアルゴリズムのバックテスト結果が返ってきます。

from jinja2 import Template

symbols = [3276, 2117, 4581, 6620, 7022]
source2 = Template(my_template).render({'symbols': symbols})

# バックテストパラメータ
bt_parameter = {
    'engine': 'maron-0.0.1b',
    'from_date': '2017-01-01',
    'to_date': '2018-09-01',
    'capital_base': 10000000}

p = qx.project(prjct_hash)
p.upload_source(source2)
bt = p.backtest(bt_parameter)
join = bt.join()
summary = join.summary()
symbol_summary = join.symbol_summary()
summary

銘柄毎の実行は

## 銘柄ごとのサマリーを見ると指定した銘柄が実行されているのがわかりますね.
join.symbol_summary()

#終わりに
Google Colaboratory初めて使いました。
Jupyter notebookも素人なので特訓したいと思います。
ちなみにJupyterの読み方はジュピターなんでしょうか?ジュパイターなんでしょうか?

Pyfolioというライブラリーを使ってバックテスト結果を描画できるそうなので、そちらも近日Qiitaにあげる予定です。

間違いや改善点を見つけた方がいらっしゃいましたら、教えてくださると幸いです。

追記

この記事を参考にさせていただきました。
https://qiita.com/akihirosasaki/items/e50bdeaa9ca58970629f
ちなみにDockerを入れなくてもローカル環境下でQunatX_SDKをインストールして、アクセスキーを入れればJupyter notebook上で普通に動きます。

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

10
10
1

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
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?