😤『国内FXでもゴトー日やりたい!』GMOコインAPIで自動売買を作る全手順 - Python + GCF で24時間稼働
こんな悩みありませんか? 😭
- 「MT4のゴトー日EA、国内FXでも使いたいんだけど…」 - MT4対応の国内業者は限られてる
- 「GMOコインでFXできるの?APIも使えるらしいけど…」 - ドキュメント見ても謎だらけ
- 「VPS借りてPython動かし続けるの、お金かかりすぎない?」 - サーバー代で利益が消える
- 「深夜のゴトー日タイミング、起きてられない…」 - 人間には限界がある
私も最初は「海外FXでゴトー日やってるけど、国内業者でも同じことできないかな…」って思ってました。でも調べてみると、GMOコインには外国為替FX APIがあるし、GCF (Google Cloud Functions) を使えばほぼ無料で24時間自動売買ができることが分かったんです!
しかも最小100通貨から取引可能で、30日間無料トライアルもある!これは試さない手はない 💪
この記事で作るもの
ゴトー日判定 → GMOコイン 外国為替FX API → USD/JPY 売買 ↑Cloud Scheduler(定期実行)→ Cloud Functions(Python)完成イメージ:
- 毎日決まった時間にCloud Schedulerが起動
- Cloud FunctionsでPythonスクリプトが実行
- ゴトー日&時間帯なら自動でドル円をエントリー/決済
- あなたは寝てても、仕事してても、24時間稼働!
参考リポジトリ
今回のロジックは、こちらのMT4/MT5用ゴトー日EAを参考にしています:
🔗 harukihosono/GotobiEA - MQL4/MQL5版ゴトー日EA
このEAの売買ロジックをPythonに移植して、GMOコインの外国為替FXで動かします。
Step 1: GMOコインの準備
1-1. 口座開設とAPIキー取得
まずはGMOコインで口座を開設し、外国為替FXのAPIキーを発行します。
- GMOコイン公式サイト にアクセスして口座開設
- ログイン後、外国為替FX口座を開設
- マイページにて、メニュー → API を選択
- 外国為替FX用のAPIキーを新規追加
APIキー発行時の設定:
- ラベル:「ゴトー日Bot」など分かりやすい名前
- 権限:外国為替FX取引(出金権限は絶対に付けないこと!)
- IP制限:空欄でOK(後から設定も可能)
⚠️ 重要:API Secretはこのとき一度しか表示されません!必ず誰にも見られない場所にコピーして保管してください。
1-2. APIの仕組みを少しだけ理解する
GMOコインのAPIと安全に通信するために、いくつかの「お作法」があります。特に、他人になりすまして勝手に取引されないための「認証」の仕組みが重要です。
Public API と Private API
APIには、誰でも情報を取得できるPublic API(例: 現在のレート取得)と、認証が必要なPrivate API(例: 注文、残高確認)の2種類があります。
Private APIの認証の仕組み(レストランの予約のイメージ)
Private APIを使うときは、自分が本物のユーザーであることを証明するために、リクエストの都度、以下の3つの情報を送る必要があります。
API-KEY(会員証)- 「私はGMOコインの会員です」と名乗るためのID。GMOコインで発行したAPIキーがこれにあたります。
API-TIMESTAMP(予約時刻)- 「このリクエストは、2025年12月7日10時0分0秒に送りました」というタイムスタンプ。古いリクエストが攻撃者に再利用されるのを防ぎます。
API-SIGN(秘密のサイン)- これが最も重要です。
API-KEY(会員証)とAPI-SECRET(秘密の合言葉)を知っている人しか作れない、一回限りの特別な署名です。 - 作り方: 「予約時刻」+「注文内容」などの情報を、あなただけが知っている「秘密の合言葉(
API-SECRET)」を使って特殊な方法で暗号化したものが「サイン(API-SIGN)」になります。 - GMOコイン側は、受け取ったリクエスト情報と、GMOコイン側で保管しているあなたのAPIシークレットを使って同じようにサインを計算し、送られてきたサインと一致するかを確認します。一致すれば、間違いなく本人からのリクエストだと判断できます。
- これが最も重要です。
この複雑な「サイン」を作る処理は、あとで紹介する gmo_fx_client.py の中で自動的に行われるので、あなたが毎回計算する必要はありません。仕組みだけ、なんとなく理解しておけば大丈夫です。
Step 2: GCP環境の準備
次に、作成するプログラムを24時間動かすためのクラウド環境(Google Cloud Platform)を準備します。
2-1. GCPプロジェクトの準備とAPI有効化
- Google Cloud Console にアクセスし、Googleアカウントでログインします。
- 新規プロジェクトを作成します(例:
gotobi-fx-bot)。 - プロジェクトの課金を有効化します。この記事で使うサービスは無料枠が大きいため、通常は料金は発生しません。
- 以下のリンクをクリックし、今回の開発で必要な各サービス(API)を有効にしてください。
2-2. Secret ManagerでAPIキーを安全に保管する
プログラムコードの中に直接APIキーを書き込むのは非常に危険です。GCPの Secret Manager という金庫のようなサービスを使い、APIキーを安全に保管しましょう。
- GCPコンソールのメニューから
セキュリティ>Secret Managerを選択します。 - 「シークレットを作成」をクリックします。
- 名前:
gmo-fx-api-keyと入力します。 - シークレットの値: GMOコインで取得した APIキー を貼り付けます。
- 「シークレットを作成」をクリックします。
- 同様に、名前を
gmo-fx-api-secret、シークレットの値にGMOコインの APIシークレット を設定し、もう一つ作成します。
2-3. ポジションを記録する箱(Firestore)を準備する
プログラムは実行が終わるたびに状態を忘れてしまうため、「今、自分が買いポジションを持っているのか」を覚えておく場所が必要です。そのためのデータベースとして Firestore を準備します。
- GCPコンソールのメニューから
データベース>Firestoreを選択します。 - 「データベースを作成」をクリックします。
- ネイティブモードを選択: 「
Native Mode」を選びます。 - ロケーションを選択:
asia-northeast1(東京) など、日本に近い場所を選びます。 - 「データベースを作成」をクリックします。
Step 3: 自動売買スクリプトの作成
環境の準備が整ったので、いよいよ自動売買を行うPythonスクリプトを作成します。全部で4つのファイルを作成し、一つのフォルダにまとめます。
3-1. プロジェクト構成
gotobi-gmo-fx/├── main.py # メインスクリプト├── gmo_fx_client.py # GMOコインFX API クライアント├── gotobi_logic.py # ゴトー日判定ロジック└── requirements.txt # 依存パッケージ3-2. GMOコイン FX APIクライアント
gmo_fx_client.py というファイル名で作成します。GMOコインAPIとの通信を担う重要な部品です。
# gmo_fx_client.pyimport hmacimport hashlibimport timeimport requestsimport jsonfrom datetime import datetime
class GMOFXClient: """ GMOコイン外国為替FX APIと通信するためのクライアントクラス。 APIへのリクエスト、署名生成、各種データ取得・注文機能をカプセル化します。 """
def __init__(self, api_key: str, api_secret: str): """ クライアントの初期化。APIキーとシークレットを設定します。 """ self.api_key = api_key self.api_secret = api_secret self.private_endpoint = 'https://forex-api.coin.z.com/private' self.public_endpoint = 'https://forex-api.coin.z.com/public'
def _create_signature(self, timestamp: str, method: str, path: str, body: str = '') -> str: """ APIリクエストに必要な署名を生成します。(Private APIでのみ使用) GMOコインのAPI仕様で定められたルールに従い、 「タイムスタンプ + HTTPメソッド + パス + リクエストボディ」 という文字列を、APIシークレットを使って暗号化(HMAC-SHA256)します。 これにより、リクエストが改ざんされておらず、正規のユーザーからのものであることを証明します。 """ text = timestamp + method + path + body sign = hmac.new( bytes(self.api_secret.encode('ascii')), bytes(text.encode('ascii')), hashlib.sha256 ).hexdigest() return sign
def _get_timestamp(self) -> str: """ APIリクエストに使用するUNIXタイムスタンプ(ミリ秒)を取得します。 """ return '{0}000'.format(int(time.mktime(datetime.now().timetuple())))
def _private_request(self, method: str, path: str, body: dict = None) -> dict: """ Private API(認証が必要なAPI)へのリクエストを送信する共通関数。 署名の生成とヘッダーの設定を自動で行います。 """ timestamp = self._get_timestamp() body_str = '' if body is None else json.dumps(body)
headers = { 'API-KEY': self.api_key, 'API-TIMESTAMP': timestamp, 'API-SIGN': self._create_signature(timestamp, method, path, body_str), 'Content-Type': 'application/json' } url = self.private_endpoint + path if method == 'GET': response = requests.get(url, headers=headers) elif method == 'POST': response = requests.post(url, headers=headers, data=body_str) return response.json()
def get_assets(self) -> dict: """ 資産残高(取引余力、証拠金維持率など)を取得します。 """ return self._private_request('GET', '/v1/account/assets')
def get_positions(self, symbol: str = None) -> dict: """ 現在保有しているポジション(建玉)の一覧を取得します。 """ path = '/v1/openPositions' if symbol: path += f'?symbol={symbol}' return self._private_request('GET', path)
def place_order( self, symbol: str, side: str, size: int, execution_type: str = 'MARKET', time_in_force: str = 'FAK' ) -> dict: """ 新規の成行注文を実行します。 """ path = '/v1/order' body = { 'symbol': symbol, 'side': side, 'executionType': execution_type, 'size': str(size), 'timeInForce': time_in_force } return self._private_request('POST', path, body)
def close_all_positions(self, symbol: str, side: str) -> list: """ 指定した通貨ペアのポジションをすべて決済します。 """ results = [] positions = self.get_positions(symbol) if positions.get('status') != 0: return [{'error': positions}] for position in positions.get('data', {}).get('list', []): if (position['side'] == 'BUY' and side == 'SELL') or (position['side'] == 'SELL' and side == 'BUY'): result = self._private_request('POST', '/v1/closeOrder', { 'symbol': symbol, 'side': side, 'executionType': 'MARKET', 'size': str(position['size']), 'positionId': position['positionId'], 'timeInForce': 'FAK' }) results.append(result) return results3-3. ゴトー日判定ロジック
gotobi_logic.py というファイル名で作成します。いつ取引するかの頭脳部分です。
# gotobi_logic.pyfrom datetime import datetime, timedeltaimport calendar
def is_gotobi(target_date: datetime = None) -> bool: """ 指定された日付がゴトー日(五十日)に該当するかを判定します。 """ if target_date is None: target_date = datetime.now() day = target_date.day weekday = target_date.weekday() if day % 5 == 0 and weekday < 5: return True if weekday == 4: tomorrow = target_date + timedelta(days=1) day_after_tomorrow = target_date + timedelta(days=2) if tomorrow.month == target_date.month and tomorrow.day % 5 == 0: return True if day_after_tomorrow.month == target_date.month and day_after_tomorrow.day % 5 == 0: return True return False
def is_buy_time(current_time: datetime = None) -> bool: """ 買いエントリーの時間帯(日本時間 2:00 ~ 9:54)かどうかを判定します。 """ if current_time is None: current_time = datetime.now() hour, minute = current_time.hour, current_time.minute return (2 <= hour <= 8) or (hour == 9 and minute <= 54)
def is_sell_time(current_time: datetime = None) -> bool: """ 売りエントリーの時間帯(日本時間 9:55 ~ 14:59)かどうかを判定します。 """ if current_time is None: current_time = datetime.now() hour, minute = current_time.hour, current_time.minute return (hour == 9 and minute >= 55) or (10 <= hour <= 14)
def is_close_time(current_time: datetime = None) -> bool: """ ポジションを決済する時間帯(日本時間 15:00以降)かどうかを判定します。 """ if current_time is None: current_time = datetime.now() return current_time.hour >= 15
def get_action(current_time: datetime = None) -> str: """ 現在の時刻情報に基づいて、実行すべきアクションを決定します。 """ if current_time is None: current_time = datetime.now() if current_time.weekday() >= 5 or not is_gotobi(current_time): return 'WAIT' if is_buy_time(current_time): return 'BUY' elif is_sell_time(current_time): return 'SELL' elif is_close_time(current_time): return 'CLOSE' else: return 'WAIT'3-4. メインスクリプト
main.py というファイル名で作成します。全体の司令塔となる最も重要なファイルです。
# main.pyimport osimport loggingfrom datetime import datetimefrom gmo_fx_client import GMOFXClientfrom gotobi_logic import get_action, is_gotobifrom google.cloud import firestore
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')logger = logging.getLogger(__name__)
SYMBOL = 'USD_JPY'ORDER_SIZE = 100
db = firestore.Client()POSITION_DOC_REF = db.collection('bot_state').document('gotobi_position')
def save_position_state(state: str): try: POSITION_DOC_REF.set({'position': state, 'timestamp': firestore.SERVER_TIMESTAMP}) logger.info(f"ポジション状態をFirestoreに保存: {state}") except Exception as e: logger.error(f"ポジション状態の保存に失敗: {e}")
def load_position_state() -> str: try: doc = POSITION_DOC_REF.get() if doc.exists: state = doc.to_dict().get('position') logger.info(f"Firestoreからポジション状態を読込: {state}") return state return None except Exception as e: logger.error(f"ポジション状態の読込に失敗: {e}") return None
def run_trading_bot(): current_position = load_position_state() api_key = os.environ.get('GMO_FX_API_KEY') api_secret = os.environ.get('GMO_FX_API_SECRET') if not api_key or not api_secret: logger.error('APIキーが設定されていません') return {'status': 'error', 'message': 'API keys not configured'}
client = GMOFXClient(api_key, api_secret) now = datetime.now() action = get_action(now) logger.info(f'現在時刻: {now}, ゴトー日: {is_gotobi(now)}, 判定アクション: {action}, 現在ポジション: {current_position}') result = {'timestamp': str(now), 'action': action, 'executed': False}
try: if action == 'BUY' and current_position != 'LONG': if current_position == 'SHORT': logger.info('既存ショートポジションを決済') client.close_all_positions(SYMBOL, 'BUY') logger.info(f'ロングエントリー実行: {SYMBOL} {ORDER_SIZE}通貨') response = client.place_order(SYMBOL, 'BUY', ORDER_SIZE) if response.get('status') == 0: save_position_state('LONG') result['executed'] = True elif action == 'SELL' and current_position != 'SHORT': if current_position == 'LONG': logger.info('既存ロングポジションを決済') client.close_all_positions(SYMBOL, 'SELL') logger.info(f'ショートエントリー実行: {SYMBOL} {ORDER_SIZE}通貨') response = client.place_order(SYMBOL, 'SELL', ORDER_SIZE) if response.get('status') == 0: save_position_state('SHORT') result['executed'] = True elif action == 'CLOSE' and current_position is not None: side_to_close = 'SELL' if current_position == 'LONG' else 'BUY' logger.info(f'{current_position} ポジションを決済 (実行サイド: {side_to_close})') client.close_all_positions(SYMBOL, side_to_close) save_position_state(None) result['executed'] = True else: logger.info('取引条件を満たさないため待機') except Exception as e: logger.error(f'取引処理中に予期せぬエラーが発生: {e}') result['error'] = str(e) return result
def gotobi_trading(request): return run_trading_bot()
if __name__ == '__main__': from dotenv import load_dotenv load_dotenv() print(run_trading_bot())3-5. 依存パッケージ
requirements.txt というファイル名で作成します。
# requirements.txtfunctions-framework==3.*requests>=2.28.0python-dotenv>=1.0.0google-cloud-firestore>=2.13.0Step 4: ローカルでテスト(任意)
クラウドにデプロイする前に、自分のPCでスクリプトが意図通りに動くかテストすることをおすすめします。
- PCに Python をインストールします。
- 作成した4つのファイル(
main.pyなど)を保存したフォルダで、ターミナル(コマンドプロンプト)を開きます。 pip install -r requirements.txtを実行して、必要なライブラリをインストールします。GMO_FX_API_KEYとGMO_FX_API_SECRETを環境変数として設定します。(.envファイルを作成するのが簡単です)python main.pyを実行して、エラーが出ずにログが表示されることを確認します。
⚠️ 注意:このテストでも実際のAPIに接続するため、注文サイズは最小(100通貨)にしておきましょう。
Step 5: GCFへのデプロイと定期実行設定
いよいよクラウドに配置して、24時間自動で動くようにします。
5-1. Cloud Functionsにデプロイする
- 事前準備:
main.py,gmo_fx_client.py,gotobi_logic.py,requirements.txtの4つのファイルを、一つのフォルダにまとめてZIPファイルに圧縮しておきます。 - GCPコンソールで Cloud Functions のページを開き、「ファンクションを作成」をクリックします。
- 環境は
第2世代、関数名はgotobi-fx-trading、リージョンはasia-northeast1(東京)などを選択します。 - トリガーは
HTTP、認証は未認証の呼び出しを許可を選択します。 - 「次へ」をクリックし、ソースコード設定で
ZIP uploadを選択し、作成したZIPファイルをアップロードします。 - ランタイムは
Python 3.12、エントリポイントはgotobi_tradingと入力します。 - **環境変数、ビルド...**の項目を開き、「セキュリティとイメージ」タブの「シークレット」で、Step 2で作成した
gmo-fx-api-keyとgmo-fx-api-secretを、それぞれ環境変数GMO_FX_API_KEYとGMO_FX_API_SECRETとして参照設定します。 - 「デプロイ」をクリックします。完了まで数分かかります。
5-2. Cloud Schedulerでボットを定期実行する
作成した関数を、決まった時間に自動実行するよう設定します。
- GCPコンソールで Cloud Scheduler を開きます。
- 「ジョブを作成」をクリックし、以下の3つのジョブをそれぞれ作成します。
- ジョブ1(朝の買い判定):
- 名前:
gotobi-morning-trigger - 頻度:
0 2 * * 1-5(平日の毎朝2:00) - タイムゾーン:
日本標準時 (Asia/Tokyo) - ターゲット:
HTTP - URL: 先ほどデプロイしたCloud FunctionsのトリガーURL
- 名前:
- ジョブ2(昼の売り判定):
- 名前:
gotobi-noon-trigger - 頻度:
55 9 * * 1-5(平日の毎朝9:55) - URL: 同上
- 名前:
- ジョブ3(夕方の決済):
- 名前:
gotobi-close-trigger - 頻度:
0 15 * * 1-5(平日の毎日15:00) - URL: 同上
- 名前:
- ジョブ1(朝の買い判定):
これでシステム構築は完了です!
Step 6: 運用と発展
6-1. ログの確認方法
ボットが想定通りに動いているか、エラーが発生していないかは、Cloud Functionsの**「ログ」**タブからいつでも確認できます。取引が実行されたか、エラーが出ていないか、定期的にチェックしましょう。
6-2. 月次コスト目安
この構成の場合、各サービスの無料枠の範囲内で収まることがほとんどで、GCPの月額費用はほぼ0円になる見込みです。(取引量に応じたGMOコインのAPI手数料は別途発生します)
よくあるエラーと対処法
Signature mismatch: 署名の生成が間違っています。APIキー/シークレットが正しいか、Secret Managerの設定を見直してください。Insufficient margin: 証拠金不足です。GMOコインに入金してください。Market closed: FX市場がクローズしている時間帯です(土日など)。
本番運用へのチェックリスト ✅
- 30日間無料トライアルで動作確認
- 最小ロット(100通貨)でテスト取引
- ログで数日間の動作(注文、決済、待機)を確認
- 1ヶ月間の損益確認
- ロットサイズの段階的引き上げ
免責事項 ⚠️
このコードを使用して発生した損失について、筆者は一切の責任を負いません。投資は自己責任で行い、必ず十分なテストを経てから本番運用に移行してください。
まとめ 🎉
お疲れ様でした!この記事では、GMOコインのAPIとGCPの無料サービスを活用して、24時間稼働するゴトー日自動売買ボットを構築する全手順を解説しました。
国内FX業者で、かつ少額からAPI自動売買を試せる環境は非常に貴重です。ぜひこの機会に、あなた自身の自動売買システム作りに挑戦してみてください。きっと、最初にボットが意図通りに動いた時の感動は忘れられない体験になりますよ!
参考リンク
- GMOコイン外国為替FX APIドキュメント - 公式APIリファレンス
- GotobiEA(MQL版) - 元になったMT4/MT5用EA
- GMOコイン外国為替FX - サービス概要
- Cloud Functions公式ドキュメント - GCFの詳細な使い方
- Firestore公式ドキュメント - データベースの詳細
🎁おすすめツール・サービス
※上記リンクにはプロモーション(広告)が含まれています
量子相場謀略|ホソノP
ブログでは書けない本音のトレード戦略とEA開発の裏側を公開。 データに基づいた検証で、再現性のある手法だけをお届けします。