cTrader/cBotの開発部屋

Mr. Robo Traderの開発ブログ


cTrader/cBot プログラミングの基礎

cTraderもMT4/MT5と同様に自動売買取引機能があります。C#プログラミング言語を用いて、cTraderの取引APIを利用してcBotを作成します。MT4/5のEAでできることはcBotでも大抵できます。

cBotの作成

cTrader のメインメニューからAutomate画面を開き、cBotsタブ上の「New(新規)」ボタンをクリックして、新たに作成された「New cBot」の名前を変更します。
ソースコード・エディタにデフォルトのテンプレート・コードが作成されますので、必要なプログラムを書き加えていきます。
cBotクラス()宣言の前に、タイムゾーンやアクセス権を指定します。MT4時間に合わせるためには調整が必要となります。
OnStart()メソッドは、cBotの初期化のときに呼び出されるメソッドです。
OnTick()メソッドは、Tick毎に動作します。新規Bar毎に動作させたい場合はOnBar()メソッドを使います。
OnStop()メソッドは、cBotが停止したときに呼び出されるメソッドです。

Code

using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        protected override void OnStart()
        {
            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}


成行き注文:ExecuteMarketOrder()

例1 - 注文が成功したとき
成行き注文は、ExecuteMarketOrder()関数を使います。注文が成功したときエントリー価格を出力する方法。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, Symbol, 10000);

            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Executing Market Order to Buy 10k EURUSD
→ Executing Market Order to Buy 10k EURUSD SUCCEEDED, Position PID156168
Position entry price is 1.34577



例2 - 注文が失敗したとき
ボリューム数を無効にして、注文に失敗した場合エラーメッセージが出て、Stop()関数でその後の取引を停止させる。

Code

    [Robot(TimeZone = TimeZones.UTC)]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, Symbol, -1);

            if (!result.IsSuccessful)
                Stop();
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, h1.
Executing Market Order to Buy -1 EURUSD
→ Executing Market Order to Buy -1 EURUSD FAILED with error "BadVolume"
cBot "Sample_cBot" was stopped for EURUSD, h1.



例3 - 成行き注文のパラメーターを追加
成行き注文のパラメーター変数に、cBotラベル、StopLoss、TakeProfitを追加して、エントリー価格、ストップロスを出力する。

Code

    [Robot(TimeZone = TimeZones.UTC)]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder((TradeType.Buy, Symbol, 10000, "order 1", 10, 10);

            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
                Print("Position SL price is {0}", position.StopLoss);
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Executing Market Order to Buy 10k EURUSD (SL: 10, TP: 10)
→ Executing Market Order to Buy 10k EURUSD (SL: 10, TP: 10) SUCCEEDED, Position ID156169
Position entry price is 1.34693
Position SL price is 1.34593


ポジションの変更:ModifyPosition()

例1 - StopLossとTakeProfitの変更
TakeProfitだけ指定した成行き注文に、ModifyPosition()関数を使ってStopLossとTakeProfitの追加変更を行う。StopLossを指定してない場合は"null"を入れた後にTakeProfit(Pips値)を入れる。
ここで注意が必要なのは、ExecuteMarketOrder()関数のSLとTPは"Pips値"、ModifyPosition()関数のSLとTPは"Price値"です、間違えないように。

Code

    [Robot()]
    public class SamplecBbot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "order 1", null, 10);
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position SL price is {0}", position.StopLoss);

                var stopLoss = position.EntryPrice - 10*Symbol.PipSize;
                ModifyPosition(position, stopLoss, position.TakeProfit);

                Print("New Position SL price is {0}", position.StopLoss);
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Executing Market Order to Buy 10000 EURUSD (TP: 10)
→ Executing Market Order to Buy 10000 EURUSD (TP: 10) SUCCEEDED, Position PID5229848
Position SL price is null
Modifying position PID5229848 (SL: 1.07716, TP: 1.07916)
→ Modifying position PID5229848 (SL: 1.07716, TP: 1.07916) SUCCEEDED, Position PID5229848
New Position SL price is 1.07716


決済注文:ClosePosition()

例1 - 決済注文
成行き注文後にグロス利益(手数料スワップを含めない)が指定の金額になったらポジションを決済する。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel");
        }

        protected override void OnTick()
        {
            var position = Positions.Find("myLabel");
            if (position != null && position.GrossProfit > 10)
            {
                ClosePosition(position);
                Stop();
            }   
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Executing Market Order to Buy 10k EURUSD
→ Executing Market Order to Buy 10k EURUSD SUCCEEDED, Position PID156171
Closing position PID156171
→ Closing position PID156171 SUCCEEDED, Position PID156171
cBot "Sample_cBot" was stopped for EURUSD, m1.



例2 - 部分決済
複数の成行き注文が成立したら、次の最新バーでそれぞれのポジションから特定ラベルの指定ボリューム数だけ部分決済する。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, Symbol, 20000, "myLabel");
            ExecuteMarketOrder(TradeType.Buy, Symbol, 30000, "myLabel");
        }

        protected override void OnBar()
        {
            var positions = Positions.FindAll("myLabel", Symbol, TradeType.Buy);

            foreach (var position in positions)
            {
                if (position.Volume >= 20000)
                {
                    ClosePosition(position, 15000);
                }
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, h1.
Executing Market Order to Buy 20k EURUSD
→ Executing Market Order to Buy 20k EURUSD SUCCEEDED, Position PID664437
Executing Market Order to Buy 30k EURUSD
→ Executing Market Order to Buy 30k EURUSD SUCCEEDED, Position PID664438
Closing position PID664437 (15k)
→ Closing position PID664437 (15k) SUCCEEDED, Position PID664437
Closing position PID664438 (15k)
→ Closing position PID664438 (15k) SUCCEEDED, Position PID664438


指値注文と逆指値注文:PlaceLimitOrder()/PlaceStopOrder()

例1 - 指値注文と逆指値注文
指値と逆指値の待機注文が設定されたとき、cBotラベルとオーダーIDを表示する。

Code

[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        PlaceLimitOrder(TradeType.Buy, Symbol, 10000, Symbol.Bid, "myLimitOrder");
        PlaceLimitOrder(TradeType.Buy, Symbol, 20000, Symbol.Bid-2*Symbol.PipSize, "myLimitOrder");            
        PlaceStopOrder(TradeType.Buy, Symbol, 10000, Symbol.Ask, "myStopOrder");

        foreach (var pendingOrder in PendingOrders)
        {
             Print("Order placed with label {0}, id {1}", pendingOrder.Label, pendingOrder.Id);
        }                                
    }
}

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Placing Limit Order to Buy 10k EURUSD (Price: 1.34211)
→ Placing Limit Order to Buy 10k EURUSD (Price: 1.34211) SUCCEEDED, PendingOrder OID246324
Placing Limit Order to Buy 20k EURUSD (Price: 1.34191)
→ Placing Limit Order to Buy 20k EURUSD (Price: 1.34191) SUCCEEDED, PendingOrder OID246325
Placing Stop Order to Buy 10k EURUSD (Price: 1.34243)
→ Placing Stop Order to Buy 10k EURUSD (Price: 1.34243) SUCCEEDED, PendingOrder OID246326
Order placed with label myLimitOrder, id 246324
Order placed with label myLimitOrder, id 246325



例2 - 待機注文にパラメーター変数を追加する
待機注文にラベル名、SL、TP、期限、コメントを入れて、SL、TPの指定があれば表示する。

Code

[Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            DateTime midnight = Server.Time.AddDays(1).Date;

            PlaceLimitOrder(TradeType.Buy, Symbol, 10000, Symbol.Bid, "mySample_cBot", 10, null, midnight, "First");

            PlaceStopOrder(TradeType.Buy, Symbol, 10000, Symbol.Ask, "mySample_cBot", 10, 10, null, "Second");

            foreach (var order in PendingOrders)
            {
                var sl = order.StopLoss == null ? "" : "SL: " + order.StopLoss;
                var tp = order.TakeProfit == null ? "" : " TP: " + order.TakeProfit;

                var text = string.Format("{0} {1}", sl, tp);

                if (order.OrderType == PendingOrderType.Limit)
                    Print(order.Comment + " Limit Order " + text);
                else
                    Print(order.Comment + " Stop Order " + text);
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Placing Limit Order to Buy 10k EURUSD (Price: 1.34326, SL: 10, ExpireTime: 22/11/2013 00:00)
→ Placing Limit Order to Buy 10k EURUSD (Price: 1.34326, SL: 10, ExpireTime: 22/11/2013 00:00), SUCCEEDED, PendingOrder OID246369
Placing Stop Order to Buy 10k EURUSD (Price: 1.34359, SL: 10, TP: 10)
→ Placing Stop Order to Buy 10k EURUSD (Price: 1.34359, SL: 10, TP: 10) SUCCEEDED, PendingOrder OID246370
First Limit Order SL: 1.34226
Second Stop Order SL: 1.34259 TP: 1.34459


待機注文の変更:ModifyPendingOrder()

例1 - 待機注文のターゲット価格を変更する
待機注文のターゲット価格を変更、SL、TP、期限はそのままにする。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var price = Symbol.Ask + 10 * Symbol.PipSize;
            DateTime? expiry = Server.Time.AddHours(12);
            PlaceStopOrder(TradeType.Buy, Symbol, 10000, price, "myLabel", 10, 10, expiry);
        }

        protected override void OnBar()
        {
            foreach (var order in PendingOrders)
            {
                if (order.Label == "myLabel")
                {
                    double newPrice = Symbol.Ask + 5 * Symbol.PipSize;
                    ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime);
                }
            }
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, h1.
Placing Stop Order to Buy 10k EURUSD (Price: 1.36161, SL: 10, TP: 10, ExpireTime: 27/11/2013 21:59)
→ Placing Stop Order to Buy 10k EURUSD (Price: 1.36161, SL: 10, TP: 10, ExpireTime: 27/11/2013 21:59) SUCCEEDED, PendingOrder OID1081885
Modifying pending order OID1081885 (Price: 1.36109, SL: 10, TP: 10, ExpireTime: 27/11/2013 21:59)
→ Modifying pending order OID1081885 (Price: 1.36109, SL: 10, TP: 10, ExpireTime: 27/11/2013 21:59) SUCCEEDED, PendingOrder OID1081885


待機注文の消去:CancelPendingOrder()

例1 - 指定ラベル名の待機注文を消去
指定のラベル名を持つ待機注文をすべて消す。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnTick()
        {
            foreach (var order in PendingOrders)
            {
                if (order.Label == "myLabel")
                {
                    CancelPendingOrder(order);
                }
            }
        }
    }


ポジションのイベント:PositionOnOpened()/PositionOnClosed()

例1 - ポジションをオープンしたときのイベント予約
ポジションをオープンしたときPositionsにイベント予約して、エントリー価格を表示する。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            Positions.Opened += PositionsOnOpened;
            ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            var pos = args.Position;
            Print("Position opened at {0}", pos.EntryPrice);
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURUSD, m1.
Executing Market Order to Buy 10k EURUSD (SL: 10, TP: 10)
→ Executing Market Order to Buy 10k EURUSD (SL: 10, TP: 10) SUCCEEDED, Position PID157201
Position opened at 1.34342



例2 - ポジションをクローズしたときのイベント予約
ポジションがクローズしたときにPositionsにイベント予約して、手数料スワップを含まないGrossProfitを表示する。

Code

    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            Positions.Closed += PositionsOnClosed;
            ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
        }

        protected override void OnBar()
        {
            var position = Positions.Find("myLabel");
            if (position != null)
                ClosePosition(position);
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            var pos = args.Position;
            Print("Position closed with {0} profit", pos.GrossProfit);
        }
    }

ログ出力

cBot "Sample_cBot" was started successfully for EURGBP, m1.
Executing Market Order to Buy 10k EURGBP (SL: 10, TP: 10)
→ Executing Market Order to Buy 10k EURGBP (SL: 10, TP: 10) SUCCEEDED, Position PID50038
Closing position PID50038
→ Closing position PID50038 SUCCEEDED, Position PID50038
Position closed with -0.24 profit


非同期型の取引注文(Asynchronous execution)

 上記で説明してきた取引注文は、すべて同期型の取引注文です。同期型の取引注文は、要求をサーバーに送信し、サーバーの応答を待ってから、後続のステートメントに実行を渡します。

 一方、非同期型の取引注文は、要求がサーバーに送信されると、プログラムはサーバーからの応答を待たずに次のステートメントを実行します。非同期トレード操作に続くステートメントは、これらの要求の結果について何も想定できません。

 たとえば、非同期型の成行き注文をした場合、注文実行の返り値を待たずに実行してしまうため多重注文になる危険性が生じます。

 非同期型の注文を使用する利点は、複数のポジションを一括決済したい場合に、サーバーからの応答を待たずに一括決済してくれますので、決済時間の遅延が無く大きな利点となります。

 非同期型の取引注文については、cTrader公式ページのTrading APIを参照してください。