StreamlitでFXの自動トレード結果を表示する

プログラミング

トレード結果やバックテストの結果を確認して問題を修正する必要があるので、バックテストの結果の見える化は必須です。データ分析でよく利用されるStreamlitを使って結果を表示する方法を解説します。

環境セットアップ

mt5を利用しpythonトレードプログラムを試す に記載した方法で、VSCode、MT5、GitGithubからのプログラムのダウンロードを行って、venvの作成、requirements.txt記載のライブラリinstallまで完了させてください。

Streamlit実行について

StreamlitはPythonで簡単にwebアプリを作成可能なライブラリです。
グラフ表示やそれに絡む機能が充実しており、データ分析などでよく利用されます。

Streamlitを実行するための設定は、.vscode/launch.jsonに記載しています。

        {
            "name": "st debug",
            "type": "python",
            "request": "launch",
            "module": "streamlit",                 // appの代わりにコレ
            "console": "integratedTerminal",
            "env": {
                "PYTHONPATH": "${workspaceFolder}",
            },
            "args": [                              // オプションはコレ
                "run",
                "view_result.py",
                "--server.port",
                "8502"
            ]
        },

この設定で、./view_result.pyを実行され、streamlitをポート番号8502で起動されます。
VSCodeの左の虫マークを選んで、”RUN NAD DEBUG”の右からst debugを選択して、緑△を押下するとstreamlitが起動します。

streamlitが起動するとブラウザが起動しファイル選択画面が表示されます。

[Browse files]ボタンを押して、./data/test_macd.csvを選択してください。このファイルは、mt5を利用しpythonトレードプログラムを試す で実行した結果をcsvにして格納しています。

ファイルを選択すると、csvのファイルの内容を表で表示し、結果の期間のローソク足と、結果をグラフっ表示します。
結果はトレード開始時刻の価格と、トレード終了時刻の価格を買いが青、売りが黄色で線引きしています。

グラフを見ると、折り返しを起点にトレードを開始しているので、macdのゴールデンクロスの判定に正しく反応できていそうですが、折り返しですぐに反応しすぎているのと、大きなトレンドは全く無視して損失を出していることがわかります。emaの期間を延ばして反応をもう少し鈍くしたり、上位足のMAなどを考慮にいれトレンド判定と合わせると効果が出そうです。

プログラム説明

import datetime
import numpy as np
import pandas as pd
import plotly.graph_objs as go
import streamlit as st
from mt5.mt5_terminal import Mt5Terminal

def custom_date_parser(x):
    try:
        return datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S%z')
    except ValueError:
        return datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S.%f%z')

def main():
    st.set_page_config(layout="wide")
    symbol = "USDJPY"
    gran = 'M1'
    mt5 = Mt5Terminal()
    uploaded_file = st.file_uploader("Choose a file", type='csv', key='csv_file')
    if uploaded_file is not None:
        # CSVファイルから
        df_result = pd.read_csv(uploaded_file, parse_dates=['start_time', 'end_time'], date_parser=custom_date_parser)
        df_result = df_result.iloc[:, 1:]
        st.dataframe(df_result)
        from_time = df_result.start_time[0] - datetime.timedelta(hours=1)
        to_time = df_result.iloc[-1].end_time + datetime.timedelta(hours=1)
        df = mt5.get_candle_from_to(symbol, gran, from_time, to_time)
        data1 = [go.Candlestick(x=df.index,
                                open=df.open,
                                high=df.high,
                                low=df.low,
                                close=df.close)]
        fig = go.Figure(data=data1)
        for idx in df_result.index:
            row = df_result.loc[idx]
            s_idx = row.start_time
            e_idx = row.end_time
            s_price = row.start_price
            e_price = row.end_price
            fig.add_trace(
                go.Scatter(
                    x=[s_idx, e_idx],
                    y=[s_price, e_price],
                    mode="lines",
                    # line=dict(color='blue') if row.result == "GET" else dict(color='yellow'),
                    line=dict(color='blue') if row.action == "BUY" else dict(color='yellow'),
                    showlegend=False
                ))
        fig.update_layout(
            height=1000,
            hovermode='x unified',
            # hovermode='y unified',
        )
        st.plotly_chart(fig, use_container_width=True)

if __name__ == '__main__':
    main()

ここからプログラムが開始されます。まずmain関数がcallされます。

if __name__ == '__main__':
    main()

streamlitの描画設定で、画面幅をワイドにします。

def main():
    st.set_page_config(layout="wide")

MT5からローソク足データをDataframe形式で取得するためのクラスMT5Terminalクラスをインスタンス化しておきます。

    mt5 = Mt5Terminal()

トレード結果を保存したcsvファイルを選択するファイルブラウザを配置します。ファイルが選択されるとuploaded_fileにファイルパスが格納され、if分の中に処理が移ります。

    uploaded_file = st.file_uploader("Choose a file", type='csv', key='csv_file')
    if uploaded_file is not None:

csvファイルを読みだして、Dataframe形式にします。1列目には無効な行があるので除きます。そのごst.dataframe()でstreamlitで読みだしたデータを表で表示します。

        df_result = pd.read_csv(uploaded_file, parse_dates=['start_time', 'end_time'], date_parser=custom_date_parser)
        df_result = df_result.iloc[:, 1:]
        st.dataframe(df_result)

トレード結果のトレード時刻からローソク足データを取得するための取得開始時間と、終了時間をそれぞれ、トレード結果期間より1時間外側にセットし、ローソク足データを取得します。

        from_time = df_result.start_time[0] - datetime.timedelta(hours=1)
        to_time = df_result.iloc[-1].end_time + datetime.timedelta(hours=1)
        df = mt5.get_candle_from_to(symbol, gran, from_time, to_time)

Plotlyというグラフ描画ライブラリを使用しローソク足データ描画設定をします。

        data1 = [go.Candlestick(x=df.index,
                                open=df.open,
                                high=df.high,
                                low=df.low,
                                close=df.close)]
        fig = go.Figure(data=data1)

トレード結果データを1件ずつ取り出して、グラフ上にトレード開始価格から、終了価格に線を引く設定をします。

        for idx in df_result.index:
            row = df_result.loc[idx]
            s_idx = row.start_time
            e_idx = row.end_time
            s_price = row.start_price
            e_price = row.end_price
            fig.add_trace(
                go.Scatter(
                    x=[s_idx, e_idx],
                    y=[s_price, e_price],
                    mode="lines",
                    # line=dict(color='blue') if row.result == "GET" else dict(color='yellow'),
                    line=dict(color='blue') if row.action == "BUY" else dict(color='yellow'),
                    showlegend=False
                ))

最後にグラフ描画のためのレイアウト設定を行い、描画処理を実行します。

        fig.update_layout(
            height=1000,
            hovermode='x unified',
            # hovermode='y unified',
        )
        st.plotly_chart(fig, use_container_width=True)

これで表とグラフが描画されます。グラフは拡大したりカーソルを合わせることでデータの詳細を表示することが可能です。

コメント