発注の結果を知りたい
発注したらその結果どうなったか知りたいですよね。cAlgoの発注メソッドはすべて結果を表すオブジェクトを返すようになっています。この中身を調べることで発注結果の詳細がわかります。
TradeResultクラス
同期系の注文はすべてこの型を結果として返します。
public class TradeResult : Object
トレード結果を保持するクラスです。
プロパティ
(bool) IsSuccessfull
発注が成功したかどうかを取得します。
(ErrorCode) Error
エラーコードを取得します。エラーでなければnullが入ってます。
(Position) Position
ポジションがかかわる注文に成功した場合、対象のPositionを取得できます。
(PendingOrder) PendingOrder
待機注文がかかわる注文に成功した場合、対象のPendingOrderを取得できます。
サンプルコード
// 1万通貨発注して結果をログに出力
TradeResult result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
string priceFmt = ":f" + Symbol.Digits.ToString();
if (result.IsSuccessful) {
var pos = result.Position;
string type = (pos.TradeType == TradeType.Buy ? "買い" : "売り");
Print("{0}を{1" + priceFmt + "}で{2}ました", pos.SymbolName, pos.EntryPrice, type);
} else {
Print("発注に失敗しました。エラー:{0}", result.Error.ToString());
}
TradeOperationクラス
Asyncと末尾についてる非同期発注メソッドはすべてこの型を返します。
public class TradeOperation : Object
リファレンスにはなぜかコンストラクタとSetResultメソッドの説明がありますが、protectedなので使えません。継承すれば使えますが、使いどころがわかりません。
プロパティ
(bool) IsExcuting
実行中かどうか。これがfalseになったら注文完了。
(TradeResult) TradeResult
トレード結果。IsExcutingがTrueの間はnull
サンプルコード
先にダメな例を。
// (フリーズします。実行しないでください。)
// 先に発注送ってから、急ぎの処理して、そのあと終わったか確認するつもり。
var operation = ExecuteMarketOrderAsync(TradeType.Sell, SymbolName, 10000);
//----
//---- なんか急ぎでやりたい処理
//----
while (operation.IsExecuting) ;
Print("完了!");
処理の内容にもよるものの、このコードは高確率でフリーズします。一見、発注が終わるまで無限ループ回してるだけのように見えますが、これだと発注が通っても、IsExcutingがfalseになることができないため、無限ループを抜けられずPrintまでたどり着けません。
どうしてもこうしたいなら途中でAlgoのメソッドRefreshData()を呼び出します。
// (多分フリーズしない版)
// 先に発注送ってから、急ぎの処理して、そのあと終わったか確認する。
var operation = ExecuteMarketOrderAsync(TradeType.Sell, SymbolName, 10000);
//----
//---- なんか急ぎでやりたい処理
//----
while (operation.IsExecuting){
RefreshData();
}
Print("完了!");
あまり褒められたコードではありませんが、一応これなら無限ループは避けられます。
個人的にはAsync系の結果確認が必要ならコールバックを設定しておく方がいいと思います。
ErrorCode列挙型
TradeResult.Errorに入ってるエラーの原因を表します。
BadVolume | 発注数量がおかしい。 |
InvalidRequest | 無効なリクエスト。 |
InvalidStopLossTakeProfit | 無効なストップロス、テイクプロフィット。 |
EntityNotFound | 対象のポジション、注文が存在しない。 |
NoMoney | 資金不足。 |
Disconnected | サーバーと通信できてない。 |
MarketClosed | マーケットが閉まってる。 |
UnknownSymbol | 指定された通貨ペアが存在しない。 |
Timeout | 時間切れ。 |
TechnicalError | 拒否されたなど、上記以外のエラー。 |
どんなときにどのエラーが起きるのか把握しておくと対処しやすいです。 (特に最初のうちは) BadVolumeとInvalidRequestをよく見ると思います。
BadVolumeは小さすぎ、大きすぎ、半端な数の発注数量を指定した時に返ってきます。Symbol.NormalizeVolumeInUnitsを通して適正量にしましょう。
InvalidResuestの原因はいろいろあるんですが、よくあるパターンはストップロスとテイクプロフィットを指定するPipsの小数点以下の桁数がおかしいときです。
値動き以上に細かい桁数でPipsに渡すとInvalidRequestになります。(そのくらい自動補正してくれてもいいのに・・・)stopPIpsとtakeprofitPIpsはMath.Roundで適正に丸め処理を行ってからOrderメソッドに渡しましょう。
InvalidStopLossTakeProfitはストップロステイクプロフィット修正時に0以下や、現在設定値と全く同じ価格など、無効な価格を指定しようとしたときに返ってきます。
EntityNotFoundはすでに決済済みのPositionやキャンセル済みのPendingOrderに対して処理をしようとしたときに返ってきます。
あとはほぼ文字通りで、最後のTechnicalErrorはその他エラーと考えてください。例えば今の価格からかけ離れた価格でExecuteMarketRangeOrderをいれたりすると返ってきます。
発注の度に確認はめんどい、でもエラーが起きたら知りたい
そんなときのためかどうか知りませんが、そういうこともできるようになってます。RobotのOnError()をオーバーライドするだけです。どこかで発注のエラーが起きるたびにOnErrorの処理が走ります。
Errorインターフェース
OnErrorに渡される引数の型です。そのためだけの型です。(ややこしいですがTradeResultのErrorプロパティはErrorCode型です。)
public interface Error
プロパティ
(ErrorCode) Code
エラーコードを取得します。
(TradeResult) TradeResult
このエラーに紐づくトレード結果情報を取得します。