【プログラミング初心者でも安心!】TradingViewのシグナルでMT4を動かす自動売買システム構築ガイド
「TradingViewで考えた最高の戦略、寝ている間も自動で取引してくれたらいいのに…」 「でも、プログラミングは難しそうだし、専用のサーバーを借りるのもお金がかかるし…」
そんな悩みを解決するのが、この記事です!
ここでは、プログラミングの専門知識がなくても、基本的に無料で使えるGoogleのクラウドサービスを「通訳」役にして、TradingViewからの売買シグナルをMT4に伝える方法を、一つ一つ丁寧に解説します。
【このシステムを一言でいうと…】 TradingViewが「今だ!買いだ!」と叫んだら、通訳(Cloud Functions)がその声を聞いて、MT4に「はい!買います!」と命令を伝えてくれる、全自動の連絡網を作るようなイメージです。
さあ、あなただけの自動売買システム作りに挑戦してみましょう!
システムの仕組み(全体像)
このシステムがどんな風に動くのか、全体の流れを追いかけてみましょう。
登場人物と役割
- TradingView: 売買のタイミングを考える司令塔。
- Webhook (ウェブフック): TradingViewが「今だ!」と叫ぶ声を伝えるための通信手段。
- Cloud Functions (GCF): TradingViewの声をMT4が分かる言葉に「通訳」してくれる、Googleの便利な無料プログラム。
- Firestore (ファイアストア): 通訳された命令を一時的に保管しておくための、Googleの無料データベース(高性能なメモ帳)。
- MT4 EA: あなたのPCで動く、実際に売買を行う兵隊。
注文が実行されるまでの流れ
graph TD A[TradingViewでシグナル発生] -->|Webhookで通知| B(Cloud Functions); B -->|命令を書き込む| C(Firestore); D(MT4のEAが定期的に見にくる) -->|命令を読み取る| C; D -->|読み取った命令を実行| E[MT4で売買実行!];- TradingView が「買い!」や「売り!」のシグナルを見つけます。
- そのシグナルは Webhook という仕組みで、インターネットを通じて Cloud Functions に送られます。
- Cloud Functions は受け取ったシグナルを「買い注文」「売り注文」というデータに整理して、Firestore というデータベースに書き込みます。
- あなたのパソコンで動いている MT4 EA が、数秒おきにFirestoreをチェックし、新しい命令が来ていないか確認します。
- 新しい命令を見つけたら、EAがあなたのMT4口座で売買を実行します!
このように、複数のサービスが連携して、全自動の取引が実現します。次のステップから、これらの仕組みを一つずつ作っていきましょう。
ステップ1:命令を保管する「箱」を準備する (Firestoreの設定)
まずは、TradingViewからの売買命令を一時的に保管しておくための「箱」の役割を果たす、Firestoreというデータベースを準備しましょう。
Firestoreのセットアップ手順
- GCPコンソール(Google Cloudの管理画面)にログインし、左上のメニューから
データベース>Firestoreを選択します。 - 「データベースを作成」をクリックします。
- ネイティブモードを選択: 「
Native Mode」を選びます。これはFirestoreの標準的なモードです。 - ロケーションを選択: 「
asia-northeast1(東京)」や「asia-northeast2(大阪)」など、日本に近い場所を選ぶと通信が少し速くなるのでおすすめです。 - 「データベースを作成」をクリックします。作成には少し時間がかかります。
これで、命令を保管する箱の準備は完了です。
ステップ2:通訳役のプログラムを配置する (Cloud Functionsのデプロイ)
次に、TradingViewからのシグナルをMT4が分かる言葉に「通訳」してくれるプログラム(Cloud Functions)を準備し、次のステップで作成するソースコードを配置(デプロイ)します。
Cloud Functionsのデプロイ手順
-
Cloud Functionsのページを開く
- GCPコンソールのメニューから「Cloud Functions」を選択し、「ファンクションを作成」をクリックします。
-
関数の基本設定
- 環境:
第1世代を選択します。(プログラムの実行環境の世代です。迷ったらこちらを選びましょう) - 関数名:
tradingview-webhookなど、分かりやすい名前を付けます。 - リージョン: 先ほどFirestoreで選んだ場所と同じリージョン(例:
asia-northeast1)を選ぶと、効率よく動作します。 - トリガーのタイプ:
HTTPを選択します。(インターネット経由でこの関数を呼び出すための設定です) - 認証:
未認証の呼び出しを許可にチェックを入れます。(これにより、TradingViewからパスワード無しで簡単にシグナルを送れるようになります) - 「保存」をクリックして、次の設定に進みます。
- 環境:
-
ソースコードの貼り付け場所の確認
- 下にある「ランタイム、ビルド、接続の設定」などをクリックして開きます。
- ランタイム:
Python 3.9を選択します。(プログラムを動かすための言語バージョンです) - ソースコード:
インライン エディタが選択されていることを確認します。 - エントリポイント:
hello_worldと入力します。(Webhookからの通知があったときに、最初に動き出す関数の名前です)
通訳プログラムのソースコード
いよいよ、Cloud Functionsで動かすPythonのコードを作成します。以下の2つのファイルをインラインエディタに貼り付けてください。
main.py
これがメインの通訳プログラムです。TradingViewからの注文を受け取ってFirestoreに保存し、MT4からの問い合わせに応答します。
from google.cloud import firestoreimport json
def hello_world(request): """ TradingViewからのWebhook受信とMT4への注文情報提供
この関数は2つの役割を持っています: 1. TradingViewからの注文を受け取り、Firestoreに保存する 2. MT4からの問い合わせに対して、Firestoreから注文情報を取得して返す """ request_json = request.get_json() order = "" symbol = ""
# JSONからパラメータ取得 if request_json and 'order' in request_json: order = request_json['order'] if request_json and 'symbol' in request_json: symbol = request_json['symbol']
print(f"受信したJSON: order={order}, symbol={symbol}")
if order == "": # MT4からの注文情報取得リクエスト # (orderが空 = 「今の注文状態を教えて」という問い合わせ) state = load_order(symbol) return {"order": state} else: # TradingViewからの注文保存リクエスト # (orderがある = 「この注文を保存して」という依頼) update_order(symbol, order) return {"res": "ok"}
def update_order(symbol, order): """ 注文情報をFirestoreに保存
TradingViewから「買い」「売り」などの注文が来たら、 この関数でFirestoreに記録します。 """ if symbol and order: db = firestore.Client() doc_ref = db.collection("TradingView").document(symbol) doc_ref.set({ "order": order, "timestamp": firestore.SERVER_TIMESTAMP }) print(f"注文保存: {symbol} - {order}")
def load_order(symbol): """ Firestoreから注文情報を取得
MT4が「今どんな注文が来てる?」と聞いてきたら、 この関数でFirestoreから最新の注文情報を返します。 """ if symbol: db = firestore.Client() doc = db.collection("TradingView").document(symbol).get()
if doc.exists: data = doc.to_dict() return data.get("order", "none") else: return "none"
return "none"requirements.txt
Cloud Functionsが必要とするライブラリ(部品)のリストです。これがないとプログラムが動きません。
google-cloud-firestorefunctions-frameworkデプロイの完了
2つのファイルを貼り付けたら、「デプロイ」ボタンをクリックしてください。デプロイには数分かかることがあります。
デプロイが完了すると、トリガータブに https://asia-northeast1-あなたのプロジェクト.cloudfunctions.net/tradingview-webhook のようなURLが表示されます。このURLをメモしておいてください! 後でTradingViewとMT4の設定で使います。
ステップ3:司令塔を設定する (TradingViewのアラート)
次に、司令塔であるTradingViewで、売買シグナルが発生したときに先ほどのURLへ通知を送るための「アラート」を設定します。
Pine Script戦略の例
まずは、どんな条件でアラートを出すかを決めるストラテジー(戦略)が必要です。ここでは簡単なRSIを使った戦略を例として紹介します。ご自身の戦略に合わせて書き換えてください。
//@version=5strategy("GCF連携戦略", overlay=true)
// パラメータrsi_period = input.int(14, "RSI期間")rsi_oversold = input.int(30, "RSI買われすぎ")rsi_overbought = input.int(70, "RSI売られすぎ")
// インジケータ計算rsi = ta.rsi(close, rsi_period)
// エントリー条件long_condition = rsi < rsi_oversoldshort_condition = rsi > rsi_overbought
// 注文実行if long_condition strategy.entry("Long", strategy.long, comment="buy") if short_condition strategy.entry("Short", strategy.short, comment="sell")
// 決済条件if strategy.position_size > 0 and rsi > rsi_overbought strategy.close("Long", comment="buy_close") if strategy.position_size < 0 and rsi < rsi_oversold strategy.close("Short", comment="sell_close")Webhookアラートの設定
ストラテジーをチャートに適用したら、アラートを作成します。
- チャート上部の「アラート」ボタン(目覚まし時計のアイコン)をクリックします。
- 条件: アラートを出すストラテジー(例:
GCF連携戦略)を選択します。 - メッセージ: ここに、Cloud Functionsに送るJSON形式のデータを記述します。
JSON{"symbol":"{{ticker}}", "order":"{{strategy.order.comment}}"}
- 通知タブ: 「Webhook URL」にチェックを入れ、先ほどCloud FunctionsでコピーしたURLを貼り付けます。
- 「作成」ボタンを押して、アラートを有効にします。
注文コメントの標準化
main.py は、comment="" で指定された文字列を見て売買を判断します。Pine Script側で、以下のようにコメントを統一しておきましょう。
// 使用する注文コメントcomment = "buy" // ロングエントリーcomment = "buy_close" // ロング決済comment = "sell" // ショートエントリーcomment = "sell_close" // ショート決済ステップ4:兵隊を配置する (MT4 EAの設定)
最後に、あなたのPCで実際に売買を行う兵隊(EA)を設定します。
EAのソースコード (MQL4)
MT4のMetaEditorを開き、新しいEAを作成して以下のコードを貼り付けてください。
基本構造とパラメータ
web_hook_url には、Cloud FunctionsのWebhook URLを忘れずに設定してください。
//+------------------------------------------------------------------+//| GCF TradingView連携EA |//+------------------------------------------------------------------+#property strict
// パラメータinput string web_hook_url = "https://your-project.cloudfunctions.net/webhook";input string input_symbol = ""; // 通貨ペア(空白の場合は自動)input int magic_number = 124455;input double qty = 0.1; // ロット数input int input_spread = 30; // スプレッド制限input int input_slippage = 20; // スリッページ制限メイン処理
void OnTick() { string order = ""; static datetime prev_time = iTime(NULL, 0, 0); // スプレッドチェック if(Ask - Bid <= input_spread * _Point) { // 1分足の更新時のみ実行 if(prev_time == iTime(NULL, 0, 0)) { return; } // 秒数制限(サーバー負荷対策) if(Seconds() < 2) { return; } prev_time = iTime(NULL, 0, 0); order = web_request(); } // ポジション管理 if(position_count(OP_BUY) > 0) { if(order == "buy_close") { position_close(OP_BUY); } } if(position_count(OP_SELL) > 0) { if(order == "sell_close") { position_close(OP_SELL); } } // エントリー処理 if(order == "buy") { position_entry(OP_BUY); } if(order == "sell") { position_entry(OP_SELL); }}Webリクエスト処理
string web_request() { static string prev_state = ""; string url = web_hook_url; string headers; string data; char post[], result[]; // 通貨ペア設定 string symbol = Symbol(); if(input_symbol != "") { symbol = input_symbol; } // リクエスト作成 headers = "Content-Type: application/json\r\n"; data = "{\"symbol\":\"" + symbol + "\"}"; ArrayResize(post, StringToCharArray(data, post, 0, WHOLE_ARRAY, CP_UTF8) - 1); // HTTP POST実行 int rest = WebRequest("POST", url, headers, 5000, post, result, headers); string order = CharArrayToString(result); StringReplace(order, "\"", ""); if(rest != 200) { Print(Symbol(), " エラー: ", CharArrayToString(result)); return ""; } else { // 同じ状態の重複実行防止 if(prev_state == CharArrayToString(result)) { return ""; } if(prev_state == "") { prev_state = CharArrayToString(result); return ""; } prev_state = CharArrayToString(result); if(order == "buy" || order == "buy_close" || order == "sell" || order == "sell_close") { Print(Symbol(), " 注文受信: ", CharArrayToString(result)); return order; } } return "";}ポジション管理関数
int position_count(int side) { int count = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderType() == side && OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number) { count++; } } } return count;}
void position_entry(int side) { if(side == OP_BUY) { OrderSend(NULL, side, qty, Ask, 0, 0, 0, NULL, magic_number, 0, clrGreen); } if(side == OP_SELL) { OrderSend(NULL, side, qty, Bid, 0, 0, 0, NULL, magic_number, 0, clrRed); }}
void position_close(int side) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderType() == side && OrderSymbol() == Symbol() && OrderMagicNumber() == magic_number) { OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0, clrBlue); } } }}MT4側の設定
EAをチャートに適用する前に、MT4自体の設定が必要です。
- WebRequestの許可設定
- MT4のメニューから
ツール→オプション→エキスパートアドバイザタブを開きます。 - 「WebRequestを許可する」にチェックを入れます。
- 下の入力欄に、Cloud FunctionsのWebhook URL(
https://...から始まるアドレス)を追加します。
- MT4のメニューから
- EAをチャートに適用
- 作成したEAをチャートにドラッグ&ドロップします。
- 「パラメータの入力」タブで、
web_hook_urlが正しいことを確認します。 - 「全般」タブで、「自動売買を許可する」にチェックが入っていることを確認して「OK」をクリックします。
- MT4上部の「自動売買」ボタンがON(緑色)になっていることを確認します。
これで全ての準備が整いました!TradingViewでアラートが発生すれば、このEAが自動で売買を実行します。
発展編:セキュリティを少しだけ強化する
このシステムは、URLを知っていれば誰でもシグナルを送れてしまいます。ここでは、最低限のセキュリティ対策として「特定の注文しか受け付けないようにする」方法を紹介します。
データ検証を組み込む
想定外の通貨ペアや注文(例: buy や sell 以外)が送られてきても無視するように、main.py の hello_world 関数を少し改造しましょう。
改造前の hello_world 関数の一部抜粋:
def hello_world(request): # ... (前略) order = request_json.get('order', '') symbol = request_json.get('symbol', '')
# --- MT4からの確認か、TradingViewからの新規注文かで処理を分ける --- # ... (後略)改造後:
以下の ---ここから追加--- と ---ここまで追加--- の部分を、あなたの main.py に書き足してみてください。
def hello_world(request): # ... (前略) order = request_json.get('order', '') symbol = request_json.get('symbol', '')
# ---ここから追加--- # 対応する通貨ペアと注文の種類をあらかじめ決めておく VALID_SYMBOLS = ["USDJPY", "EURJPY", "GBPJPY", "BTCUSD"] VALID_ORDERS = ["buy", "sell", "buy_close", "sell_close"]
# もし注文(order)があり、かつそれが許可された注文リストに含まれていない場合はエラー if order and order not in VALID_ORDERS: print(f"エラー:許可されていない注文です: {order}") return {"error": "Invalid order type"}, 400
# もし通貨ペア(symbol)があり、かつそれが許可された通貨ペアリストに含まれていない場合はエラー if symbol and symbol not in VALID_SYMBOLS: print(f"エラー:許可されていない通貨ペアです: {symbol}") return {"error": "Invalid symbol type"}, 400 # ---ここまで追加---
# --- MT4からの確認か、TradingViewからの新規注文かで処理を分ける --- # ... (後略)このように、受け付ける symbol と order を限定することで、意図しない命令でEAが動いてしまうのを防ぐことができます。VALID_SYMBOLS のリストは、ご自身が取引する通貨ペアに合わせて自由に変更してください。
さらに高度なセキュリティ対策
今回は紹介しませんが、以下のような方法でさらにセキュリティを強化することも可能です。興味がある方は調べてみてください。
- API認証: TradingViewからの通知に「合言葉」を含めてもらい、正しい合言葉を知っている相手からの通知だけを受け付けるようにする。
- リクエスト制限: 特定のIPアドレスから、1分間に何回も通知が送られてくるような攻撃を防ぐ。
まずはデータ検証をしっかり行い、安全な自動売買システムの第一歩を踏み出しましょう。
うまくいかない時は?(トラブルシューティング)
自動売買システムの構築では、小さな設定ミスが原因でうまく動かないことがよくあります。焦らず、以下の点を確認してみましょう。
Cloud Functionsの「ログ」を確認する習慣をつけよう
一番の頼りになるのが、Cloud Functionsのログです。ログは、プログラムが動いたときの「足跡」のようなもので、エラーの原因を探るための最大のヒントになります。
ログの確認方法:
- GCPコンソールでCloud Functionsのページを開きます。
- 作成した関数名をクリックします。
- **「ログ」**タブをクリックします。
ここに、「受信したJSON: ...」や「エラー: ...」といった、main.pyのprint()で出力したメッセージが表示されます。エラーメッセージ(赤い文字で表示されることが多いです)をよく読んで、何が起きているのかを確認しましょう。
よくある問題と解決策
問題1:TradingViewでアラートが鳴っても、Firestoreにデータが書き込まれない
- 原因A:Webhook URLが間違っている
- 確認方法: TradingViewのアラート設定にあるWebhook URLと、Cloud Functionsの「トリガー」タブに表示されているURLが完全に一致しているか、一文字ずつ確認してください。余計なスペースが入っていることもあります。
- 原因B:TradingViewからの通知がCloud Functionsに届いていない
- 確認方法: Cloud Functionsのログを見て、
受信したJSON:というメッセージが表示されているか確認します。表示されていなければ、通知自体が届いていません。TradingViewのWebhook設定を見直しましょう。
- 確認方法: Cloud Functionsのログを見て、
- 原因C:Firestoreへの書き込み権限がない
- 確認方法: Cloud Functionsのログに
Permission deniedや403といったエラーが出ていないか確認します。もし出ていたら、GCPのIAMというメニューで、Cloud Functionsが使っているサービスアカウントにCloud Datastore ユーザーのロール(役割)が付与されているか確認してください。(通常は自動で設定されます)
- 確認方法: Cloud Functionsのログに
問題2:MT4のEAが注文を実行しない
- 原因A:MT4側でWebRequestが許可されていない
- 確認方法: MT4の
ツール>オプション>エキスパートアドバイザタブで、「WebRequestを許可する」にチェックが入っているか、そして許可URLのリストにCloud FunctionsのURLが正しく登録されているか確認します。
- 確認方法: MT4の
- 原因B:MT4からCloud Functionsへの通信ができていない
- 確認方法: MT4のターミナル(表示されていなければ
Ctrl+T)の「Experts」タブに、web_request()からのエラーメッセージが出力されていないか確認します。URLの間違いや、PCのファイアウォールが通信をブロックしている可能性があります。
- 確認方法: MT4のターミナル(表示されていなければ
- 原因C:Firestoreから "none" しか返ってこない
- 確認方法: MT4のログで、
注文受信:のメッセージが表示されず、常に空の状態であれば、Firestoreから正しい注文データを取得できていない可能性があります。main.pyのload_order関数や、Firestoreにデータが正しく書き込まれているかを確認しましょう。
- 確認方法: MT4のログで、
問題3:デプロイでエラーが発生する
- 原因A:
requirements.txtの書き間違い- 確認方法: ライブラリ名(
google-cloud-firestore,functions-framework)が正しく書かれているか確認します。
- 確認方法: ライブラリ名(
- 原因B:Pythonコードの文法エラー
- 確認方法: デプロイ時のエラーメッセージに、
SyntaxErrorやIndentationErrorといった表示がないか確認します。これは、コードのインデント(字下げ)が崩れている場合によく発生します。Pythonはインデントが非常に重要なので、コピー&ペーストした際に崩れていないか確認しましょう。
- 確認方法: デプロイ時のエラーメッセージに、
ここに書かれていない問題に遭遇した場合は、ログに出力されたエラーメッセージをコピーして、Googleで検索してみるのが解決への近道です。
まとめ
この連携システムにより、以下が実現できます:
メリット:
- TradingViewの高度な分析機能活用
- クラウドベースの安定稼働
- 複数MT4との同時連携
- リアルタイムでの注文同期
注意点:
- ネットワーク遅延の考慮
- APIクォータの管理
- セキュリティ対策の徹底
- 適切な監視体制の構築
このシステムを基に、さらなる機能拡張や最適化も可能です。安全で効率的な自動売買環境を構築してください。
🎁おすすめツール・サービス
※上記リンクにはプロモーション(広告)が含まれています
量子相場謀略|ホソノP
ブログでは書けない本音のトレード戦略とEA開発の裏側を公開。 データに基づいた検証で、再現性のある手法だけをお届けします。