# ネイティブプロトコル概要

moomoo API は、moomoo が主要プログラミング言語(Python、Java、C#、C++、JavaScript)向けに提供する API SDK です。呼び出しを容易にし、戦略開発の難易度を下げます。
このセクションでは、戦略スクリプトと OpenD サービス間の通信に使用する低レベルプロトコルについて説明します。上記5種類以外のプログラミング言語のユーザーがネイティブプロトコルを実装する際に参考にしてください。

ご注意

  • お使いのプログラミング言語が上記5種類に含まれる場合は、このセクションをスキップしてください。

# プロトコルリクエストフロー

  • 接続の確立
  • 接続の初期化
  • データリクエストまたはプッシュデータの受信
  • 定期的に KeepAlive を送信して接続を維持

proto-process

# プロトコル設計

プロトコルデータにはプロトコルヘッダーとプロトコルボディが含まれます。ヘッダーは固定フィールド、ボディは具体的なプロトコルに依存します。

# プロトコルヘッダー

struct APIProtoHeader
{
    u8_t szHeaderFlag[2];
    u32_t nProtoID;
    u8_t nProtoFmtType;
    u8_t nProtoVer;
    u32_t nSerialNo;
    u32_t nBodyLen;
    u8_t arrBodySHA1[20];
    u8_t arrReserved[8];
};
1
2
3
4
5
6
7
8
9
10
11
フィールド 説明
szHeaderFlag パケットヘッダー開始フラグ。固定値 "FT"
nProtoID プロトコル ID
nProtoFmtType プロトコル形式タイプ。0 は Protobuf 形式、1 は Json 形式
nProtoVer プロトコルバージョン。互換性のためのイテレーション用。現在は 0 を指定
nSerialNo パケットシーケンス番号。リクエストとレスポンスの対応に使用。インクリメントが必要
nBodyLen パケットボディの長さ
arrBodySHA1 パケットボディの元データ(復号後)の SHA1 ハッシュ値
arrReserved 8バイト拡張予約

ご注意

  • u8_t は8ビット符号なし整数、u32_t は32ビット符号なし整数を表します
  • OpenD の内部処理は Protobuf を使用するため、Json 変換のオーバーヘッドを減らすために Protobuf 形式の使用を推奨します
  • nProtoFmtType フィールドでボディのデータ型を指定すると、レスポンスは対応する型で返されます。プッシュプロトコルのデータ型は OpenD の設定ファイルで指定します
  • arrBodySHA1 はリクエストデータのネットワーク転送前後の整合性検証に使用されます。正しく入力する必要があります
  • プロトコルヘッダーのバイナリストリームはリトルエンディアンバイトオーダーを使用します。ntohl 等の関数でのデータ変換は通常不要です

# プロトコルボディ

# Protobuf プロトコルリクエストボディ構造

message C2S
{
    required int64 req = 1;
}

message Request
{
    required C2S c2s = 1;
}
1
2
3
4
5
6
7
8
9

# Protobuf プロトコルレスポンスボディ構造

message S2C
{
    required int64 data = 1;
}

message Response
{
    required int32 retType = 1 [default = -400]; //RetType、戻り値
    optional string retMsg = 2;
    optional int32 errCode = 3;
    optional S2C s2c = 4;
}
1
2
3
4
5
6
7
8
9
10
11
12
フィールド 説明
c2s リクエストパラメータ構造
req リクエストパラメータ。実際にはプロトコル定義に従う
retType リクエスト結果
retMsg リクエスト失敗時の失敗理由
errCode リクエスト失敗時の対応エラーコード
s2c レスポンスデータ構造。一部のプロトコルはデータを返さないためこのフィールドなし
data レスポンスデータ。実際にはプロトコル定義に従う

ご注意

  • パケットボディ形式はリクエストのプロトコルヘッダー nProtoFmtType で指定し、OpenD のプッシュ形式は InitConnect で設定します。
  • 元のプロトコルファイル形式は Protobuf で定義されています。JSON 形式での転送が必要な場合は、protobuf3 のインターフェースで直接 JSON に変換することを推奨します。
  • 列挙値フィールドは符号付き整数で定義され、コメントで対応する列挙を示します。列挙は通常 Common.proto、Qot_Common.proto、Trd_Common.proto ファイルで定義されています。
  • プロトコル内の価格・パーセンテージ等のデータは浮動小数点型で転送されるため、直接使用すると精度の問題が発生します。精度(プロトコルで未指定の場合はデフォルト小数点以下3桁)に基づいて四捨五入してから使用してください。

# ハートビート保持

syntax = "proto2";
package KeepAlive;
option java_package = "com.moomoo.openapi.pb";
option go_package = "github.com/moomooopen/mmapi4go/pb/keepalive";

import "Common.proto";

message C2S
{
	required int64 time = 1; //クライアントがパケット送信時のUTCタイムスタンプ(秒)
}

message S2C
{
	required int64 time = 1; //サーバーがレスポンス送信時のUTCタイムスタンプ(秒)
}

message Request
{
	required C2S c2s = 1;
}

message Response
{
	required int32 retType = 1 [default = -400]; //RetType、戻り値
	optional string retMsg = 2;
	optional int32 errCode = 3;
	
	optional S2C s2c = 4;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  • 概要

    ハートビート保持

  • プロトコル ID

    1004

  • 使用方法

    初期化接続で返されるハートビート間隔に基づいて、OpenD にハートビートプロトコルを送信します

# 暗号化通信フロー

  • OpenD で暗号化が設定されている場合、InitConnect 初期化接続プロトコルは RSA 公開鍵で暗号化する必要があります。後続の他のプロトコルは InitConnect が返すランダム鍵を使用して AES 暗号化通信を行います。
  • OpenD の暗号化フローは SSL プロトコルを参考にしていますが、一般的にローカルデプロイであることを考慮し、関連フローを簡略化しています。OpenD と接続クライアントは同一の RSA 秘密鍵ファイルを共有します。秘密鍵ファイルの保管・配布には十分注意してください。
  • このサイトでランダムな RSA 鍵ペアをオンライン生成できます。鍵形式は PCKS#1、鍵長 512 または 1024、パスワードは未設定とし、生成された秘密鍵をファイルにコピー保存して、OpenD 設定rsa_private_key 項目に秘密鍵ファイルパスを設定してください。
  • 本番取引を行うユーザーは暗号化の設定を推奨します。アカウントおよび取引情報の漏洩を防止します。

encrypt

# RSA 暗号化・復号

  • OpenD 設定rsa_private_key に秘密鍵ファイルパスを指定
  • OpenD と接続クライアントは同一の秘密鍵ファイルを共有
  • RSA 暗号化・復号は InitConnect リクエストにのみ使用し、他のリクエストの対称暗号化 Key を安全に取得するために使用
  • OpenD の RSA 鍵は 1024 ビット。パディング方式 PKCS1、公開鍵で暗号化・秘密鍵で復号。公開鍵は秘密鍵から生成可能
  • Python API 参考実装:RsaCrypt クラスの encrypt / decrypt インターフェース

# 送信データの暗号化

  • RSA 暗号化ルール:鍵ビット数が key_size の場合、1回の暗号化文字列の最大長は (key_size)/8 - 11 です。現在 1024 ビットのため、1回の暗号化長は 100 に設定できます。
  • 平文データを最大100バイトの小セグメントに分割して暗号化し、各セグメントの暗号化データを連結したものが最終的な Body 暗号化データになります。

# 受信データの復号

  • RSA 復号も同様にセグメント分割ルールに従います。1024 ビット鍵の場合、各セグメントの復号データ長は 128 バイトです。
  • 暗号文データを128バイトの小セグメントに分割して復号し、各セグメントの復号データを連結したものが最終的な Body 復号データになります。

# AES 暗号化・復号

  • 暗号化 Key は InitConnect プロトコルから返される
  • デフォルトでは AES の ECB 暗号化モードを使用
  • Python API 参考実装: ConnMng クラスの encrypt_conn_data / decrypt_conn_data インターフェース

# 送信データの暗号化

  • AES 暗号化はソースデータ長が16の倍数である必要があるため、'0'でパディングしてから暗号化し、mod_len をソースデータ長と16の剰余として記録します。
  • 暗号化前にソースデータを変更する可能性があるため、暗号化データの末尾に16バイトのパディングブロックを追加します。最後の1バイトに mod_len を、残りのバイトに'0'を設定し、暗号化データとパディングブロックを連結して最終的な送信プロトコルの body データとします。

# 受信データの復号

  • プロトコル body データの最後の1バイトを取り出して mod_len とし、末尾16バイトのパディングブロックを切り落としてから復号します(暗号化時のパディングロジックに対応)。
  • mod_len が 0 の場合、復号後のデータがそのままプロトコルの body データです。0 以外の場合は末尾の (16 - mod_len) バイトのパディングデータを切り落とす必要があります。

aes