見出し画像

#AI自作 No.15: OANDA証券 MT5ティックデータの一括取得スクリプト

こんばんは。
本日は、AI自作シリーズで記事にしたヒストリカルデータの一括ダンウロードの続編記事です。

こちら⬇️の記事でご紹介したティックデータと言われるデータを使う必要ができました。

この記事では、このティックデータを一括でダウンロードするために作成したスクリプトをご紹介、共有したいと思います。

背景

こちら ⬇️ のマガジンでご紹介している『高い勝率で利小損大を乗り切る』方針のFXトレード戦略を運用しています。

今年から開発を始めた新しい利小損大戦略Bのデモ口座の運用を始めたところ、バックテストの結果との乖離が非常に大きくなりました。

調べたところバックテストとデモ口座の乖離が大きくなる理由の一つには、バックテストで利用されるデータとデモ・リアル口座とのデータの差異があります。
この戦略Bでは、比較的高頻度で取引を行うため、このデータの差異が大きな乖離となってしまったと考えています。
これまでMT4で運用をしてきましたが、MT4でのバックテストではリアル口座で処理されるティックデータとは全く異なった仕組みで処理されるようです。
MT4では、ヒストリカルデータは最小単位として1分足データでインポートできますが、そのデータからバックテストで使用されるティックデータはMT4が内部的に(ある意味適当に)作成するという仕組みになっています。
この違いにより、どうしてもリアル口座と同じ動きにすることができないようです。
有償のデータ・ツールなどを利用してやる方法はあるようですが、そのデータにしても実際に運用するFX会社の配信データとは必ずしも一致しません。
スプレッドなどは各社固有ですし、価格データ自体も微妙な差異はあるものと想像します。

このあたりを調べている中で、このMT4の制約がMT5ではなくなるということを知りました。
MT5ではリアル口座で処理されるティックデータを取り込んでバックテストが行えるようです。

ただし、日本でMT5を提供している会社はほとんどなくスプレッド・手数料的に検討できる会社としては、OANDA証券だけでした。
私がメインで考えている EURUSD通貨ペアについては、FXTFがスプレッド 0.3 pipsのところ、OANDA 0.5 pipsでした。
FXTFは手数料が少しかかるので、差は 0.1 pips程度です。

OANDA証券では、このティックデータをリアル口座で実際に配信されたデータとしています。

画像

これは、つまりリアル口座と「ほぼ」同じ処理がバックテストで再現できるということではないでしょうか?

MT4でリアル口座との差に苦労している私にとっては、かなり衝撃的なうれしい発見でした。

OANDA証券ティックデータの問題

太っ腹なOANDA証券で非常に評価が高いですが、このテックデータを利用する上で一つ問題がありました。
OANDA証券のサイトでは、ティックデータを1ヶ月分でしかダウンロードできません。
10年近くのデータをダウンロードするためには1通貨ペアで100回を超えるダウンロードが必要になります。
複数通貨ペア、また、CFD商品などもダウンロードしようとすると数百回のダウンロードが必要になります。

これを手動でやろうとすると気が遠くなります。
ということで、以前クリック証券からヒストリカルデータをダウンロードする際にも利用したスクリプトでの自動化を利用したいと思います。
Pythonスクリプトでダンウロードを自動化するというものです。
クリック証券とやることは同様ですが、証券会社のサイトごとに仕様が異なるので、以前のスクリプトを一部流用しつつ、ゼロから作成しました。

OANDA証券ティックデータのダウンロードの処理イメージ

まず、作成したスクリプトでダンウロードした動画イメージをこちらでご確認ください。


前回同様このスクリプトは完全自動化ではなく、途中人手での操作が必要です。
以下の2点は手動での作業となります。

  • 複数のダウンロードが同時並行で始まりますが、ブラウザから許可を求めるダイアログが表示されるので「許可する」を選択する

  • ダウンロードファイルがすべて完了した後、コマンドプロンプト画面を閉じる

ティックデータの一括ダンウロードスクリプト

太っ腹なOANDA証券で非常に評価が高いですが、このテックデータを利用す
このスクリプトではSeleniumというライブラリを利用してChromeブラウザを起動、自動操作しています。
環境に依存する部分が多分にあるため、うまく動かないケースも多々あると思います。
ご自身で、AIなどを活用しながら対応することが前提になりますのご留意ください。

以下スクリプトを共有いたします。
先頭部分の「初期設定」のユーザーIDなどを変更いただく必要があります。

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
import os
import time
import signal

# 初期設定  ----------------------
USER_ID = "XXXXXXXXXXXXXXX"
PASSWORD = "YYYYYYYYYYYYYY"
DOWNLOAD_DIR = "\\_temp"         # ティックデータをダンウロードするフォルダを指定
DOWNLOAD_INTERVAL = 1            # 各ファイルのダウンロード待機期間。短すぎるとエラーになりやすい??
CURRENCY_PAIR = "XAUUSD"         # 通貨ペア or 商品名
YEAR_START= 2025                   # ダウンロード対象開始年 (-1: 存在する最初のもの)
YEAR_END = -1                    # ダウンロード対象終了年 (-1: 存在する最後のもの)

options = webdriver.ChromeOptions()
prefs = {"download.default_directory": os.path.abspath(DOWNLOAD_DIR)}
options.add_experimental_option("prefs", prefs)

# ドライバーを自動でインストール
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=options)  ### Selenium4の場合

# 最大の読み込み時間を設定 今回は最大30秒待機できるようにする
wait = WebDriverWait(driver=driver, timeout=30)

url = "https://www.oanda.jp/trade/web/fxTradeLogin.do"
try:
    # 手順1: 指定したURLを開く
    driver.get(url)

    driver.find_element(By.NAME, "username").send_keys(USER_ID)
    driver.find_element(By.NAME, "password").send_keys(PASSWORD)

    # クッキー確認ダイアログが表示、ログイン要素を隠してしまうので execute_scriptを利用して回避
    #driver.find_element(By.NAME, "action").click()
    element = driver.find_element(By.NAME, "action")
    driver.execute_script("arguments[0].click();", element)

    # テックデータのページを開く
    element = driver.find_element(By.XPATH, '//*[@id="main"]/div[2]/div/div/article/section[4]/div[2]/div[2]/div[2]/a').click()
    wait.until(EC.presence_of_all_elements_located)

    # 通貨ペア表示セクションに移動
    element = driver.find_element(By.XPATH, '//*[@id="pairs"]')
    driver.execute_script("arguments[0].scrollIntoView({block:\"center\"});", element)

    # 通貨ペアを選択
    element = driver.find_element(By.XPATH, '//*[@id="pairs_' + CURRENCY_PAIR + '"]')
    driver.execute_script("arguments[0].click();", element)

    # 年のドロップダウンを選択
    dropdown = driver.find_element(By.XPATH, '//*[@id="yaerSelector"]')

    for option in Select(dropdown).options:
        year = option.get_attribute('value')

        if (YEAR_START == -1 or (YEAR_START <= int(year))) \
            and (YEAR_END == -1 or (YEAR_END >= int(year))):

            # 年ドロップダウンのリストを選択し
            Select(dropdown).select_by_value(year)
            print("Processing year=" + year)

            dropdown2 = driver.find_element(By.XPATH, '//*[@id="monthSelector"]')
            for option2 in Select(dropdown2).options:
                month = option2.get_attribute('value')
                Select(dropdown2).select_by_value(month)
                print("  -Processing month=" + month)

                submit = driver.find_element(By.XPATH, '//*[@id="download_btn"]')
                driver.execute_script("arguments[0].click();", submit)

                time.sleep(DOWNLOAD_INTERVAL)

    #time.sleep(300)  # ダウンロードが完了するのを5分待機
    print("Finished all downloads.")

    # ファイルダウンロードが完了するまで待機
    input()

# エラーが発生した時はエラーメッセージを吐き出す。
except Exception as e:
    print(e)
    print("An error occurred.")

# 最後にドライバーを終了する
finally:
    driver.quit()

単一の通貨ペアだけであれば手動でやってしまった方が早かったかもしれません。
しかし、このスクリプトのおかけで、EURUSD, EURJPY, USDJPY, JP225, US100, XAUUSDを手間なくダウンロードすることができました。
また、今後データが追加された場合には、このスクリプトでの自動化が役立つと思います。
多少時間がかかりましたが、結果としては作成してよかったかなと思います。

改善点などのコメントは大歓迎です。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。

#AI自作
#FXトレード
#ダウンロード自動化
#バックテスト
#Selenium
#ヒストリカルデータ
#OANDA証券
#MT5


いいなと思ったら応援しよう!

なべなべ
記事の内容を有効に活用できた、記事を気に入っていただけたようでしたらチップでサポートいただけますと嬉しいです。 また、こんなことを知りたい、あんなことができないかなど記事にしたいことがございましたら、サポートの有無にかかわらずお知らせくださいませ。

コメント

ログイン または 会員登録 するとコメントできます。
#AI自作 No.15: OANDA証券 MT5ティックデータの一括取得スクリプト|なべなべ
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1