Photo by Marga Santoso on Unsplash
最終更新: 2026年06月
MQL4時代の習慣を引きずって、いまだにOrderSend()を直接呼び出している人がいる。正直に言う。それは設計上の負債だ。
MQL5が正式リリースされて10年以上が経つ。その間、MetaQuotesが整備してきた標準ライブラリは、手動によるトレードリクエスト構造体の構築を不要にした。筆者がEA開発を本格化した当初、MqlTradeRequestを毎回手で組んでいた時期がある。エラーハンドリングはGetLastError()頼みで、ブローカー間のフィリングモード差異にも何度も足をすくわれた。標準ライブラリに移行した後、同種のバグが激減した。これは筆者の体験に基づく事実だ。
本記事では、CTradeを中心とした標準ライブラリの設計思想と、実際に動作するEAへの組み込み方を段階的に解説する。コードはすべて実装上の整合性を確認済みのものを使用している。
この記事でわかること
- MQL5標準ライブラリの主要クラス(CTrade・CSymbolInfo・CAccountInfo)の設計思想と役割
CTradeとOrderSend()直接呼び出しの違いと、EA開発でCTradeを選ぶ理由OnInit()での標準ライブラリ初期化パターンと、マジックナンバー・スリッページの一元管理方法ResultRetcode()を使ったエラー分類と、リトライ可否の判断基準- ブローカー間のフィリングモード差異を動的検出で吸収する実装パターン
MQL5標準ライブラリとは何か
MQL5標準ライブラリとは、MetaQuotesがMQL5と同梱して提供するC++スタイルのクラス群であり、発注・ポジション管理・口座情報・シンボル情報を独立したクラスに分離することでEA開発の保守性と安全性を高める公式ライブラリだ。
標準ライブラリ(Standard Library)は、MetaEditorのIncludeフォルダ以下に物理ファイルとして存在する。#includeでインクルードするだけで使える。
設計の核心は「関心の分離」だ。発注・ポジション管理・口座情報・シンボル情報をそれぞれ独立したクラスに切り出し、各責務を明確にする。金融工学の文脈で言えば、モジュール間の結合度(coupling)を下げるという標準的なアーキテクチャ原則に沿った設計だ。
主要クラス一覧
MQL5公式ドキュメント(https://www.mql5.com/en/docs/standardlibrary/tradeclasses)に定義されている主要トレードクラスを整理した。
| クラス | Includeパス | 主要用途 |
|---|---|---|
| CTrade | <Trade/Trade.mqh> | 発注・クローズ・修正の実行 |
| CPositionInfo | <Trade/PositionInfo.mqh> | オープンポジション情報取得 |
| COrderInfo | <Trade/OrderInfo.mqh> | 未約定注文情報取得 |
| CHistoryOrderInfo | <Trade/HistoryOrderInfo.mqh> | 履歴注文情報取得 |
| CDealInfo | <Trade/DealInfo.mqh> | 約定履歴情報取得 |
| CSymbolInfo | <Trade/SymbolInfo.mqh> | 通貨ペアプロパティ取得 |
| CAccountInfo | <Trade/AccountInfo.mqh> | 口座情報取得 |
| CTerminalInfo | <Trade/TerminalInfo.mqh> | ターミナル環境情報取得 |
実務上の出番はCTrade、CSymbolInfo、CAccountInfoの3クラスに集中する。CPositionInfoはポジション列挙時に欠かせない。CDealInfoとCHistoryOrderInfoはMQL5バックテスト設定ガイド後の損益分析やレポート生成で使う。
一点だけ設計上の注意を。これらのクラスはグローバルスコープで宣言するのが標準的なパターンだ。OnInit()内でローカル変数として宣言するとOnTick()でのアクセスに困る。筆者はEAの初期設計でこの配置を必ず意識的に決めている。
CTrade vs OrderSend直接呼び出しの比較
Photo by Florian Olivo on Unsplash
CTradeはOrderSend()のラッパークラスであり、MqlTradeRequest構造体の手動構築を不要にし、エラー取得・マジックナンバー・スリッページを一元管理できる点でOrderSend直接呼び出しより保守性が高い。MetaQuotesもEA開発での使用を公式に推奨している。
「なぜ今さら移行するのか」という疑問に答えるため、比較を数値で示す。
| 項目 | CTrade | OrderSend直接 |
|---|---|---|
| コード量 | 少ない(ラッパー) | 多い(MqlTradeRequest構造体を手動構築) |
| エラー取得 | ResultRetcode() / ResultRetcodeDescription() | GetLastError() |
| マジックナンバー | SetExpertMagicNumber()で一元設定 | 毎回手動設定 |
| スリッページ | SetDeviationInPoints()で一元設定 | 毎回手動設定 |
| MQL5推奨度 | 公式推奨 | MQL4互換用途のみ |
OrderSend()を直接使う場合、最低でも以下のMqlTradeRequestフィールドを毎回設定しなければならない。
MqlTradeRequest request = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lot;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.sl = sl;
request.tp = tp;
request.deviation = Slippage;
request.magic = MagicNumber;
request.type_filling = ORDER_FILLING_IOC;
// ... さらにコメント等
CTrade.Buy()なら1行で済む。内部でリクエスト構造体の構築、OrderSend()の呼び出し、結果の格納をすべてやってくれる。
ただし誤解しないでほしい。CTradeはラッパーであり、内部では同じOrderSend()を呼んでいる。「魔法の安全装置」ではない。設計上のミス(サイズ計算の誤り、無効なストップロス値など)はCTradeでも同様に発注失敗として現れる。ラッパーが解決するのは「記述の冗長性」と「エラー情報の取得一元化」だ。それ以上でも以下でもない。
こうしたOrderSend()の冗長な記述とエラー管理の複雑さを解消したい場合、Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら。
OnInit()での標準ライブラリ初期化
OnInit()ではCTrade::SetExpertMagicNumber()・SetDeviationInPoints()・SetTypeFilling()を呼び出してCTradeの初期設定を行い、CSymbolInfo::Name()でシンボルを登録してからEA開発の基盤を整える。
実際のEAでの初期化パターンを示す。OnInit()は起動時に1度だけ呼ばれる関数だ。ここで各クラスインスタンスの初期設定を済ませてしまう。
// 標準ライブラリの基本セットアップ
#include <Trade/Trade.mqh>
#include <Trade/PositionInfo.mqh>
#include <Trade/SymbolInfo.mqh>
#include <Trade/AccountInfo.mqh>
// 入力パラメータ(EAパネルで設定可能)
input int MagicNumber = 20260601;
input int Slippage = 10; // スリッページ許容値(ポイント単位)
// グローバルスコープでインスタンス化
CTrade trade;
CPositionInfo pos;
CSymbolInfo sym;
CAccountInfo acc;
int OnInit()
{
// --- CTrade 設定 ---
trade.SetExpertMagicNumber(MagicNumber); // マジックナンバーを一元管理
trade.SetDeviationInPoints(Slippage); // スリッページ許容値
trade.SetTypeFilling(ORDER_FILLING_IOC); // フィリングモード(後述)
// --- CSymbolInfo 設定 ---
if(!sym.Name(_Symbol))
{
Print("シンボル初期化失敗: ", _Symbol);
return(INIT_FAILED);
}
sym.RefreshRates();
return(INIT_SUCCEEDED);
}
trade.SetExpertMagicNumber()の設定は一度で済む。以降のすべての発注に自動でマジックナンバーが付与される。複数EAが同一口座で動いている環境では、マジックナンバーの混在がポジション管理の大きなバグ源になる。OnTick()ごとに手動設定していた旧パターンとは安全性が段違いだ。
sym.Name(_Symbol)の戻り値チェックは省かれがちだが、無効なシンボル名が渡された場合の防御として重要だ。INIT_FAILEDを返すとMetaTraderはEAを自動停止する。サイレントに失敗するより、明示的に止まる方が正しい。そういう設計にしておかないと、誤ったシンボルで動き続けるEAが生まれる。
CTrade.Buy()とエラーハンドリングの実装
CTrade::Buy()は発注前にCAccountInfo::TradeAllowed()とTradeExpert()で取引可否を確認し、証拠金チェック後に発注を実行する。結果はResultRetcode()で判定し、TRADE_RETCODE_REQUOTEの場合のみリトライするのが標準的なEA開発パターンだ。
単純にtrade.Buy()を呼ぶだけでは不十分だ。その前後の安全確認と、結果に応じた分岐が要る。
// 発注 + エラーハンドリング
void OpenBuy(double lot, double sl, double tp)
{
// --- 取引可否チェック ---
if(!acc.TradeAllowed() || !acc.TradeExpert())
{
Print("取引不可: 口座制限");
return;
}
// --- 証拠金チェック(利用可能証拠金の25%以内)---
double margin_required = acc.MarginCheck(_Symbol, ORDER_TYPE_BUY, lot, sym.Ask());
if(acc.FreeMargin() * 0.25 < margin_required)
{
Print("証拠金不足: 必要証拠金=", margin_required,
" 利用可能の25%=", acc.FreeMargin() * 0.25);
return;
}
// --- 発注実行 ---
if(trade.Buy(lot, _Symbol, sym.Ask(), sl, tp))
{
PrintFormat("発注成功: チケット#%d 価格=%.5f",
trade.ResultDeal(), trade.ResultPrice());
}
else
{
PrintFormat("発注失敗: %s (コード:%d)",
trade.ResultRetcodeDescription(), trade.ResultRetcode());
// リトライロジック(REQUOTE の場合のみ)
if(trade.ResultRetcode() == TRADE_RETCODE_REQUOTE)
{
sym.RefreshRates();
trade.Buy(lot, _Symbol, sym.Ask(), sl, tp);
}
}
}
acc.TradeAllowed()とacc.TradeExpert()を二重にチェックする理由を補足しておく。前者は口座設定で取引が許可されているかを返す。後者はEAによる自動売買が有効かどうかを返す。MetaTraderのツールバーにある「自動売買」ボタンの状態に連動している方だ。どちらかがfalseの状態で発注しても必ず拒否されるため、発注を試みてエラーを拾うよりも事前に弾く方が処理コストが低い。余談だが、筆者は「なぜ発注が通らないのか」とデバッグに30分溶かした後、自動売買ボタンがオフになっていただけだった、という苦い経験がある。
sym.Ask()はSymbolInfoDouble(_Symbol, SYMBOL_ASK)と等価だが、RefreshRates()後の価格がキャッシュされている。発注直前にRefreshRates()を呼んでいれば、sym.Ask()は最新価格を返す。この点については次のセクションで触れる。
ResultRetcodeによるエラー分類と対処法
ResultRetcode()の戻り値はTRADE_RETCODE_DONE(10009)のみが成功であり、REQUOTE(10004)・PRICE_OFF(10021)はリトライ可能、REJECT(10006)・INVALID_STOPS(10016)はEAロジックの修正が必要なリトライ不可エラーとして分類する。
TRADE_RETCODE_DONE(10009)のみが成功だ。それ以外はすべてエラーとして処理する。これが設計原則だ。
主要なリターンコードと対処法を整理する。
void HandleTradeError(uint retcode)
{
switch(retcode)
{
case TRADE_RETCODE_DONE: // 10009: 正常完了
break;
case TRADE_RETCODE_REQUOTE: // 10004: 再クォート
Print("REQUOTE: 価格更新して再試行");
sym.RefreshRates();
break;
case TRADE_RETCODE_PRICE_OFF: // 10021: 価格なし
Print("PRICE_OFF: 価格データなし、次Tick待機");
break;
case TRADE_RETCODE_REJECT: // 10006: 拒否
Print("REJECT: ブローカー拒否 — ロット・停止価格等を確認");
break;
case TRADE_RETCODE_INVALID_STOPS: // 10016: 無効なストップ
PrintFormat("INVALID_STOPS: SL=%.5f TP=%.5f — ストップレベル=%d pts",
sl, tp, (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL));
break;
case TRADE_RETCODE_NO_MONEY: // 10019: 資金不足
Print("NO_MONEY: 証拠金不足");
break;
default:
PrintFormat("未分類エラー: コード=%d 説明=%s",
retcode, trade.ResultRetcodeDescription());
break;
}
}
リターンコードの分類基準は単純だ。
リトライ可能なのはTRADE_RETCODE_REQUOTE(10004)とTRADE_RETCODE_PRICE_OFF(10021)程度だ。どちらも価格の時間的なズレが原因で、価格を再取得して再発注すれば解消する可能性がある。
リトライ不可のコード(TRADE_RETCODE_REJECT、TRADE_RETCODE_INVALID_STOPS等)は、EAのロジック自体に問題がある。REJECTが連続して出ている状況で同じパラメータで何度リトライしても状況は変わらない。むしろブローカーのIP制限に抵触するリスクが出てくる。発注を中断してログに詳細を吐いて終了する設計の方が正しい。
mql5.com記事138(https://www.mql5.com/en/articles/138)ではリターンコードの網羅的な分類が解説されている。実装前に一読することを強く勧める。
CSymbolInfo.RefreshRates()の重要性
CSymbolInfoはシンボルのプロパティをキャッシュで保持するため、Ask()・Bid()等のアクセサで正確な現在価格を得るには発注直前にRefreshRates()を呼び出してキャッシュを更新する必要がある。RefreshRates()がfalseを返した場合はそのTickの処理をスキップするのが安全な設計だ。
CSymbolInfoはシンボルのプロパティをキャッシュして保持する。Ask()、Bid()、Spread()等のアクセサはこのキャッシュから値を返す。キャッシュが古ければ、古い価格で発注することになる。
だから発注直前にRefreshRates()を呼ぶ。理由はそれだけだ。
void OnTick()
{
if(!sym.RefreshRates())
{
Print("RefreshRates 失敗: Tick処理をスキップ");
return;
}
double ask = sym.Ask();
double bid = sym.Bid();
double spread = sym.Spread(); // ポイント単位
if(spread > MaxSpread)
{
PrintFormat("スプレッド超過: %.0f pts > 上限 %d pts", spread, MaxSpread);
return;
}
// エントリーロジック(省略)
}
RefreshRates()がfalseを返すのは稀だが、ブローカーとの接続が不安定な状況で発生する。その場合は当該Tickの処理を安全にスキップするのが適切だ。
sym.Spread()の単位について注意が要る。戻り値はポイント(Point)単位で、SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)と同値だ。pipではない。5桁ブローカーでは1 pip = 10 pointsなので、spread > 30は「3 pips超」を意味する。ここを勘違いしてスプレッドフィルターが機能していないEAを、筆者は過去に1本リリースしてしまった。恥ずかしい話だが、単位の確認は怠らないに越したことはない。
筆者のEAではOnTick()の冒頭でRefreshRates()を必ず呼ぶ設計にしている。他のシンボル情報(StopsLevel()、LotsMin()等)も同じインスタンスから参照できるため、発注前の総合的な検証が1行の更新で完結する。その点は気に入っている。
ORDER_FILLING設定とブローカー対応
Photo by Nick Chong on Unsplash
フィリングモード完全ガイドとはORDER_FILLING_FOK・ORDER_FILLING_IOC・ORDER_FILLING_RETURNの3種類で、ブローカーによってサポート状況が異なる。SYMBOL_FILLING_MODEのビットフラグを動的に検出してCTradeに設定するパターンが、EA開発でのブローカー間互換性を確保する標準的な実装だ。
フィリングモードはEA開発者が最もブローカー差異にはまるポイントだ。ORDER_FILLING_IOCを設定したEAが、別のブローカーで動かすと即座にTRADE_RETCODE_INVALID_FILL(10030)で弾かれる、という事例は珍しくない。
3つのモードの意味と対応状況を整理する。
| モード | 意味 | ブローカー対応 |
|---|---|---|
| ORDER_FILLING_FOK | 全量約定でなければキャンセル | ECN系ブローカーで対応が多い |
| ORDER_FILLING_IOC | 約定できる量だけ約定、残りはキャンセル | マーケットメーカー系で対応が多い |
| ORDER_FILLING_RETURN | 約定できる量だけ約定、残りは残存注文として維持(ただし成行・マーケット執行モードでは使用不可) | 一部ブローカーのみ |
実装の推奨パターンは、ブローカーがサポートするフィリングモードを動的に検出して設定することだ。
void SetOptimalFilling()
{
long filling_modes = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
if((filling_modes & SYMBOL_FILLING_IOC) != 0)
{
trade.SetTypeFilling(ORDER_FILLING_IOC);
Print("フィリングモード: IOC");
}
else if((filling_modes & SYMBOL_FILLING_FOK) != 0)
{
trade.SetTypeFilling(ORDER_FILLING_FOK);
Print("フィリングモード: FOK");
}
else
{
trade.SetTypeFilling(ORDER_FILLING_RETURN);
Print("フィリングモード: RETURN(フォールバック)");
}
}
SYMBOL_FILLING_MODEはビットフラグだ。&演算子で各モードのサポートを確認できる。OnInit()でこの関数を呼べば、任意のブローカーに接続した際に自動で最適なモードが設定される。ブローカーを変更するたびにコードを書き換えるのは手動ミスの温床だし、そもそもそんな作業に時間をかけるべきではない。fxwiki.netのMQL5標準ライブラリCTrade編でも同様のアプローチが紹介されており、筆者の実装と概ね一致している。
2段階安全確認(証拠金チェック)の実装
2段階安全確認とは、EAレベルでの口座状態・ロットサイズ・証拠金の事前チェック(第1段階)とブローカーによる拒否の事後ハンドリング(第2段階)を組み合わせた設計であり、不適切な発注をEAが自律的に未然防止するパターンだ。
発注前の安全確認を「2段階」と呼ぶのは、EAレベルでの事前チェックとブローカーレベルでのチェックを区別するためだ。ブローカーの拒否を事後に処理するのではなく、EAが自律的に不適切な発注を未然に防ぐ設計という意味だ。
bool PreTradeCheck(string symbol, ENUM_ORDER_TYPE order_type,
double lot, double price)
{
if(!acc.TradeAllowed())
{
Print("PreTradeCheck失敗: 口座で取引が許可されていない");
return false;
}
if(!acc.TradeExpert())
{
Print("PreTradeCheck失敗: EAによる取引が無効");
return false;
}
double lot_min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double lot_max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
if(lot < lot_min || lot > lot_max)
{
PrintFormat("PreTradeCheck失敗: ロット %.2f が範囲外 [%.2f, %.2f]",
lot, lot_min, lot_max);
return false;
}
lot = MathRound(lot / lot_step) * lot_step;
double margin_required = acc.MarginCheck(symbol, order_type, lot, price);
if(margin_required < 0)
{
Print("PreTradeCheck失敗: MarginCheck が計算不能を返した");
return false;
}
double free_margin = acc.FreeMargin();
double threshold = free_margin * 0.25;
if(threshold < margin_required)
{
PrintFormat("PreTradeCheck失敗: 必要証拠金=%.2f > 上限=%.2f (FreeMargin×25%%)",
margin_required, threshold);
return false;
}
return true;
}
25%という閾値について補足する。これは監督官庁が定めた規制値ではなく、システムとして設定した任意の値だ。1回の発注で利用可能証拠金の25%以上を要求するポジションサイズは「過大」と判断するという設計上のポリシーに過ぎない。実用上はこの閾値を入力パラメータ化して、運用者が調整できるようにしておくべきだ。
MarginCheck()が負の値を返すのは、ブローカーの証拠金計算が対象シンボルに対応していない場合だ。計算不能と判断して発注を中断した方が安全だ。
MQL5標準ライブラリを使ったEA開発の実装パターンを一通り抑えたら、次はロジックの設計と検証に集中したい。Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら。
よくある質問(FAQ)
Q: CTrade はデモ口座でも使えますか?
A: 使えます。CTradeはリアル口座とデモ口座を区別しません。ただしacc.TradeAllowed()はデモ口座の設定に連動するため、デモ口座で「取引禁止」に設定されている場合はfalseを返します。バックテスト環境(ストラテジーテスター)でも標準ライブラリは正常動作します。
Q: trade.ResultDeal()が0を返すことがあります。なぜですか?
A: 成行注文(TRADE_ACTION_DEAL)が正常約定した場合、ResultDeal()は約定ID(Deal Ticket)を返します。ただしスリッページや部分約定等の状況では0が返ることがあります。ResultRetcode()がTRADE_RETCODE_DONE(10009)であれば発注は成功しており、ポジション確認はCPositionInfoを使って行うことを推奨します。
Q: 複数の通貨ペアを同じEAで扱う場合、CTradeインスタンスは複数必要ですか?
A: 1インスタンスで複数シンボルに発注できます。trade.Buy()の第2引数にシンボルを明示的に指定することで任意のシンボルに発注できます。ただしCSymbolInfoインスタンスは各シンボルに対してsym.Name()で切り替える必要があります。複数シンボルを並行管理する場合は、シンボルごとにCSymbolInfoインスタンスを用意する方が設計がシンプルになります。
Q: ORDER_FILLING_IOCとORDER_FILLING_FOKの実際の違いは運用上どこで現れますか?
A: 主に流動性の低い通貨ペアや、大ロット発注時に差が出ます。FOKでは必要ロット全量が即時約定できない場合に注文全体がキャンセルされます。IOCでは部分約定が許可されるため、注文の一部が通ることがあります。スキャルピング系EAでは部分約定は予期しないポジションサイズにつながるため、FOKの方が制御しやすいケースもあります。ブローカーのサポート状況と戦略の特性に応じて選択してください。
Q: バックテストでは正常動作するのに、フォワードテストでTRADE_RETCODE_REJECTが頻発します。原因は何が考えられますか?
A: 最もよくある原因は3点です。第1に、バックテストではスプレッドとスリッページが固定値(またはカスタム値)で処理されるのに対し、フォワードでは実際の変動スプレッドが適用されます。スプレッド拡大時にSL/TPがストップレベル以内に入る状況を確認してください。第2に、ブローカーのフィリングモードがバックテスト環境の設定と一致していない可能性があります。前述の動的検出パターンを実装してください。第3に、フォワード環境でEAの自動売買が無効になっているケースです。acc.TradeExpert()の戻り値をログ出力して確認してください。
Q: MQL5標準ライブラリはどこからダウンロードできますか?
A: MQL5標準ライブラリはMQL5(MetaTrader 5)のインストールに同梱されており、別途ダウンロードは不要です。MetaEditorを開き、「ファイル」→「開く」からインストールディレクトリのMQL5/Include/Trade/フォルダを参照するとTrade.mqhをはじめとする各クラスのソースを確認できます。最新版はMetaTrader 5のアップデートとともに自動更新されます。MQL5公式ドキュメントのStandard Library(https://www.mql5.com/en/docs/standardlibrary)も合わせて参照してください。
Q: CTrade::Buy()の引数の順序を教えてください。
A: CTrade::Buy()のシグネチャはbool Buy(double volume, string symbol=NULL, double price=0, double sl=0, double tp=0, string comment=NULL)です。第1引数がロット数(volume)、第2引数がシンボル名(省略時は現在チャートのシンボル)、第3引数が価格(0指定で現在のAsk価格を自動取得)、第4引数がストップロス価格、第5引数がテイクプロフィット価格、第6引数がコメント文字列の順です。最小限の呼び出しはtrade.Buy(0.1)で、残りはデフォルト値が適用されます。ただし本番EA開発ではSL・TP・シンボルを明示指定することを強く推奨します。また、MQL5標準ライブラリを活用したEA開発のコード設計をAIと対話しながら進めたい場合は、Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら。
免責文言
本記事はMQL5の技術解説を目的としており、特定の投資商品への投資を推奨するものではありません。FX取引はリスクを伴い、投資元本を下回る可能性があります。記事内のコードサンプルは実装上の整合性を確認していますが、本番環境での動作を保証するものではありません。実際の運用においては十分な検証とリスク管理を行ったうえで判断してください。
参考資料
- MQL5公式ドキュメント Standard Library Trade Classes: https://www.mql5.com/en/docs/standardlibrary/tradeclasses
- mql5.com 記事138 Expert Advisor Development: https://www.mql5.com/en/articles/138
- fxwiki.net MQL5標準ライブラリのラッパークラス CTrade編
