콘텐츠로 이동

cBot 코드 샘플

이 페이지는 트레이딩 봇을 생성하고 알고리즘을 개발하기 위한 여러 PythonC# 코드 예제를 제공합니다. 아래 나열된 cBot 중 어느 것도 금융 수익을 보장하지 않습니다. 라이브 계정에 인스턴스를 배포하기 전에 반드시 백테스트를 수행하고 cBot을 맞춤 설정하세요.

cBot 샘플 저장소

다양한 자동화 전략과 트레이딩 스타일을 위한 실행 준비가 된 템플릿을 포함한 포괄적인 cBot 코드 샘플은 GitHub의 별도 PythonC# 저장소에서 확인할 수 있습니다.

동기 작업

이 섹션의 모든 cBot은 동기적으로 작업을 실행합니다.

시장 주문 실행

  • 성공적인 작업을 수행하는 간단한 cBot

    다음 트레이딩 봇은 시작 시 시장 주문을 생성하고 결과를 result 변수에 저장합니다.

    주문 실행이 성공하면 진입 가격이 로그에 출력됩니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 시장 주문 실행 중
    • 10000 EURUSD 매수 시장 주문 실행 성공, 포지션 PID14576001
    • 포지션 진입 가격은 1.19067입니다.
  • 맞춤 설정 가능한 매개변수를 가진 간단한 cBot

    다양한 cBot 속성을 선언할 때 [Parameter()] 선언을 사용하여 이를 맞춤 설정 가능한 매개변수로 전환할 수 있습니다. 새 cBot 인스턴스가 시작되면 귀하(또는 다른 사용자)가 이러한 매개변수에 맞춤 값을 할당할 수 있습니다.

    다음 예제를 고려하세요.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    참고

    Python cBot은 .cs 파일에 선언된 맞춤 설정 가능한 매개변수를 사용합니다.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    위 예제에서 우리는 다음 특성을 정의합니다:

    • 매개변수의 이름. 이후 cTrader UI에 나타납니다 ("SMA Period").
    • 사용자가 변경하지 않는 한 모든 새 인스턴스에 적용될 매개변수의 기본값 (DefaultValue = 14).

    아래 코드에서는 SmaPeriod 속성이 실제 트레이딩 봇에서 어떻게 사용될 수 있는지 보여줍니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SamplecBotReferenceSMA : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }
    
        [Parameter("SMA Period", DefaultValue = 14)]
        public int SmaPeriod { get; set; }
    
        private SampleSMA sma;
    
        protected override void OnStart()
        {
            sma = Indicators.GetIndicator<SampleSMA>(Source, SmaPeriod);
        }
    
        protected override void OnTick()
        {
            Print("{0}", sma.Result.LastValue);
        }
    }
    

    참고

    Python cBot은 .cs 파일에 선언된 맞춤 설정 가능한 매개변수를 사용합니다.

    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            self.sma = api.Indicators.GetIndicator<SampleSMA>(api.Source, api.SmaPeriod)
    
        def on_tick(self):
            api.Print(f"{self.sma.Result.LastValue}")
    

    우리의 봇은 맞춤 설정 가능한 SmaPeriod 속성을 가져와 시작 시 그 값을 Indicators.GetIndicator<SampleSMA>() 메서드에 전달합니다. 이 메서드는 지정된 기간에 대한 단순 이동 평균 값을 반환합니다.

    cBot 인스턴스를 생성할 때 모든 조정 가능한 매개변수는 인스턴스 추가 창에서 설정할 수 있습니다.

    시작 시 cBot은 매 틱마다 마지막 단순 이동 평균 값이 무엇인지 알려줍니다.

    로그 출력

    • CBot 인스턴스 [Sample cBot Reference SMA, EURUSD, h1]가 시작되었습니다.
    • 0.975685714285714
    • 0.975681428571429
    • 0.97568
    • CBot 인스턴스 [Sample cBot Reference SMA, EURUSD, h1]가 사용자에 의해 중지되었습니다.
  • 추가 인수를 사용하여 시장 주문 실행

    이전 예제에서는 ExecuteMarketOrder() 메서드에 가능한 최소한의 인수를 전달했습니다. 그것들은 거래 유형 (TradeType.Buy), 심볼 (Symbol) 및 볼륨 (-1)이었습니다.

    ExecuteMarketOrder() 메서드는 Label, StopLoss, TakeProfitComment와 같은 추가 인수와 함께 호출될 수 있습니다. 아래 예제는 레이블 ("order 1"), 손절매 보호 메커니즘 (10) 및 이익실현 수준 (10)을 지정합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    [Robot(TimeZone = TimeZones.UTC)]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 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);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", 10, 10)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
                api.Print(f"Position SL price is {position.StopLoss}")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 시장 주문 실행 중 (SL: 10, TP: 10)
    • 10000 EURUSD 매수 시장 주문 실행 성공, 포지션 PID14576098
    • 포지션 진입 가격은 1.1896입니다.
    • 포지션 SL 가격은 1.1886입니다.

포지션 수정

아래 예제에서는 주문이 실행될 때 이익실현 값 (10)만 추가합니다. 이후 포지션을 수정하여 손절매를 추가합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[Robot()]
public class SamplecBbot : Robot
{
    protected override void OnStart()
    {
        var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 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);

        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Sample_cBot():
    def on_start(self):
        result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", None, 10)

        if result.IsSuccessful:
            position = result.Position
            api.Print(f"Position SL price is {position.StopLoss}")
            stopLoss = position.EntryPrice - 10 * api.Symbol.PipSize
            api.ModifyPosition(position, stopLoss, position.TakeProfit)
            api.Print(f"New Position SL price is {position.StopLoss}")

로그 출력

포지션 청산

  • 완전 청산 수행

    아래 코드 샘플은 시장 주문을 실행합니다. 결과 포지션의 총 이익이 특정 값 (null && position.GrossProfit > 10)을 초과하면 포지션이 청산됩니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, "myLabel");
        }
    
        protected override void OnTick()
        {
            var position = Positions.Find("myLabel");
            if (position != null && position.GrossProfit > 10)
            {
                ClosePosition(position);
                Stop();
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "myLabel")
    
        def on_tick(self):
            position = api.Positions.Find("myLabel")
            if position is not None and position.GrossProfit > 10:
                api.ClosePosition(position)
                api.Stop()
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 시장 주문 실행 중
    • 10000 EURUSD 매수 시장 주문 실행 성공, 포지션 PID14576180
  • 부분 청산 수행

    이전 예제를 수정하여 동일한 레이블 ("myLabel")을 가진 두 개의 시장 주문을 생성합니다. 각 새로운 바에서 우리의 트레이딩 봇은 볼륨이 20,000 이상인 경우 이 주문 중 정확히 절반을 청산합니다.

    또한 Positions.FindAll() 메서드를 사용합니다. 이 메서드는 반복할 수 있는 포지션 목록을 반환합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000, "myLabel");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 30000, "myLabel");
        }
    
        protected override void OnBar()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            foreach (var position in positions)
            {
                if (position.VolumeInUnits >= 20000)
                {
                    ClosePosition(position, 15000);
                }
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000, "myLabel")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 30000, "myLabel")
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
            for position in positions:
                if position.VolumeInUnits >= 20000:
                    api.ClosePosition(position, 15000)
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 20000 EURUSD 매수 시장 주문 실행 중
    • 20000 EURUSD 매수 시장 주문 실행 성공, 포지션 PID14579299
    • 30000 EURUSD 매수 시장 주문 실행 중
    • 30000 EURUSD 매수 시장 주문 실행 성공, 포지션 PID14579300

예약 주문 생성

  • Limit 및 Stop 주문 생성

    Limit 및 Stop 주문은 예약 주문입니다; 그럼에도 불구하고 시장 주문과 유사하게 생성됩니다. 그러나 Limit 및 Stop 주문을 생성할 때는 대상 가격을 지정해야 하며 시장 범위가 없습니다.

    이 cBot은 두 개의 Limit 주문과 하나의 Stop 주문을 생성합니다. 그런 다음 주문을 반복하고 레이블과 ID를 로그에 출력합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLimitOrder");
            PlaceLimitOrder(TradeType.Buy, SymbolName, 20000, Symbol.Bid-2*Symbol.PipSize,
                    "myLimitOrder");
            PlaceStopOrder(TradeType.Buy, SymbolName, 10000, Symbol.Ask, "myStopOrder");
    
            foreach (var pendingOrder in PendingOrders)
            {
                Print("Order placed with label {0}, id {1}", pendingOrder.Label, pendingOrder.Id);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLimitOrder")
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 20000, api.Symbol.Bid - 2 * api.Symbol.PipSize, "myLimitOrder")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "myStopOrder")
    
            for pendingOrder in api.PendingOrders:
                Print(f"Order placed with label {pendingOrder.Label}, id {pendingOrder.Id}")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 Limit 주문 실행 중 (가격: 1.19036)
    • 10000 EURUSD 매수 Limit 주문 실행 성공, 예약 주문 OID25220794
    • 20000 EURUSD 매수 Limit 주문 실행 중 (가격: 1.19017)
    • 20000 EURUSD 매수 Limit 주문 실행 성공, 예약 주문 OID25220795
    • 10000 EURUSD 매수 Stop 주문 실행 중 (가격: 1.19040)
    • 10000 EURUSD 매수 Stop 주문 실행 성공, 예약 주문 OID25220796
    • 레이블 myLimitOrder, id 25220794로 주문이 실행되었습니다.
    • 레이블 myLimitOrder, id 25220795로 주문이 실행되었습니다.
    • 레이블 myStopOrder, id 25220796로 주문이 실행되었습니다.
  • 추가 매개변수로 예약 주문 생성

    시장 주문과 마찬가지로, 주문 라벨, 다양한 보호 메커니즘, 주문 만료 날짜를 지정하고 코멘트를 제공할 수도 있습니다.

     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
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var midnight = Server.Time.AddDays(1).Date;
    
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "mySample_cBot", 10, null, midnight, "First");
    
            PlaceStopOrder(TradeType.Buy, SymbolName, 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);
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    class Sample_cBot():
        def on_start(self):
            midnight = api.Server.Time.AddDays(1).Date
    
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "mySample_cBot", 10, None, midnight, "First")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "mySample_cBot", 10, 10, None, "Second")
    
            for order in api.PendingOrders:
                sl = "" if order.StopLoss is None else f"SL: {order.StopLoss}"
                tp = "" if order.TakeProfit is None else f"TP: {order.TakeProfit}"
    
                api.Print(f"{order.Comment} {order.OrderType} Order {sl} {tp}")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 매수 지정가(Buy Limit) 주문 실행: 10000 EURUSD (가격: 1.19049, 손절매: 10, 만료 시간: 2018/05/12 00:00:00)
    • 매수 지정가(Buy Limit) 주문 실행: 10000 EURUSD (가격: 1.19049, 손절매: 10, 만료 시간: 2018/05/12 00:00:00) 성공, 예약 주문 OID25220807
    • 매수 역지정가(Buy Stop) 주문 실행: 10000 EURUSD (가격: 1.19053, 손절매: 10, 이익실현: 10)
    • 매수 역지정가(Buy Stop) 주문 실행: 10000 EURUSD (가격: 1.19053, 손절매: 10, 이익실현: 10) 성공, 예약 주문 OID25220808
    • 지정가 주문
    • 첫 번째 지정가 주문 손절매: 1.18949
    • 두 번째 역지정가 주문 손절매: 1.18953 이익실현: 1.19153

예약 주문 수정

예약 주문의 여러 특성을 수정할 수 있습니다.

아래 예제는 예약 주문의 목표 가격, 보호 수준 또는 만료 날짜 및 시간을 수정하는 방법을 보여줍니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var price = Symbol.Ask + 10 * Symbol.PipSize;
        var expiry = Server.Time.AddHours(12);
        PlaceStopOrder(TradeType.Buy, SymbolName, 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);
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        price = api.Symbol.Ask + 10 * api.Symbol.PipSize
        expiry = Server.Time.AddHours(12)

        api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, price, "myLabel", 10, 10, expiry)

    def on_bar(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                newPrice = api.Symbol.Ask + 5 * api.Symbol.PipSize
                api.ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime)

로그 출력

예약 주문 취소

주문을 취소하는 구문은 CancelPendingOrder(order)이며, 여기서 orderPendingOrder 타입입니다.

아래 예제는 "myLabel" 라벨이 있는 모든 주문을 취소하는 것을 보여줍니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel")
            {
                CancelPendingOrder(order);
            }
        }
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                api.CancelPendingOrder(order)

포지션 이벤트

다양한 트레이딩 작업과 관련된 이벤트를 구독할 수 있습니다. 예를 들어, 포지션이 열렸는지 테스트하기 위해, 모든 Position 객체에 대해 열릴 때 발생하는 이벤트를 구독합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[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);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Positions.Opened += self.on_position_opened
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_position_opened(self, args):
        pos = args.Position
        api.Print(f"Position opened at {pos.EntryPrice}")

로그 출력

마찬가지로, 포지션이 닫힐 때마다 발생하는 이벤트를 구독할 수도 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[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);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Sample_cBot():
    def on_start(self):
        api.Positions.Closed += self.on_position_closed
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_bar(self):
        position = api.Positions.Find("myLabel")

        if position is not None:
            api.ClosePosition(position);            

    def on_position_closed(self, args):
        pos = args.Position
        api.Print(f"Position closed with {pos.GrossProfit} profit")

로그 출력

좌표 변환

아래 cBot은 사용자가 차트를 오른쪽 클릭하여 적절한 방향으로 지정가 주문을 할 수 있도록 합니다. 이는 마우스 Y 좌표를 차트 Y 좌표(심볼 가격에 해당)로 변환하여 수행합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Robot(AccessRights = AccessRights.None)]
public class CoordinatesConverter : Robot
{
    protected override void OnStart()
    {
        Chart.MouseUp += Chart_MouseUp;
    }

    private void Chart_MouseUp(ChartMouseEventArgs obj)
    {
        var desiredPrice = Chart.YToYValue(obj.MouseY);
        var desiredTradeType = desiredPrice > Symbol.Bid ? TradeType.Sell : TradeType.Buy;
        PlaceLimitOrder(desiredTradeType, SymbolName, 10000, desiredPrice);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Chart.MouseUp += self.on_chart_mouse_up        

    def on_chart_mouse_up(self, args):
        desiredPrice = api.Chart.YToYValue(args.MouseY)
        desiredTradeType = TradeType.Sell if desiredPrice > api.Symbol.Bid else TradeType.Buy
        api.PlaceLimitOrder(desiredTradeType, api.SymbolName, 10000, desiredPrice)

비동기 실행

위의 코드 샘플은 동기 실행을 사용하여 트레이딩 로봇을 구현하도록 설계되었습니다. C#과 Python 모두 비동기 작업을 지원하므로, 동일한 시간대에 여러 작업을 수행할 수 있습니다.

시장 주문 비동기 실행

비동기 메서드의 구문은 동기 메서드와 유사합니다. 동일한 유형의 인수를 받지만, 반환 타입은 TradeResult 대신 TradeOperation입니다.

  • 기본 비동기 작업

    다음 cBot은 비동기 작업이 어떻게 작동하는지 보여줍니다. 시장 주문이 생성되고, 다음 조건에서 cBot은 작업이 실행 중인지 확인합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
    
            if (operation.IsExecuting)
            {
                Print("Operation Is Executing");
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
    
            if operation.IsExecuting:
                api.Print("Operation Is Executing")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 시장 주문 실행: 10000 EURUSD 매수
    • 작업 실행 중
    • 시장 주문 실행: 10000 EURUSD 매수 성공, 포지션 PID14579532
  • 주문 실행

    다음 예제는 동기와 비동기 메서드의 차이를 강조합니다.

    cBot은 비동기 메서드를 호출한 직후 작업이 실행 중인지 확인합니다. 동기 메서드를 호출한 후에도 다시 확인합니다. 이 두 작업에 대한 로그 출력은 다릅니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 시장 주문 실행: 10000 EURUSD 매수
    • 작업 실행 중
    • 시장 주문 실행: 20000 EURUSD 매수
    • 시장 주문 실행: 10000 EURUSD 매수 성공, 포지션 PID14579541
    • 시장 주문 실행: 20000 EURUSD 매수 성공, 포지션 PID14579542
    • 작업 실행됨
  • 추가 매개변수로 주문 실행

    다음 cBot은 라벨("myLabel"), 보호 수준(10, 10), 심볼(SymbolName) 및 거래량(10000)을 지정하여 주문을 실행합니다.

    이 예제는 Positions 컬렉션과 FindAll() 메서드를 포함합니다. Find()FindAll()은 동일한 라벨, 심볼 및 거래 유형을 가진 포지션을 찾는 데 사용할 수 있습니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", 10, 10);
        }
        protected override void OnTick()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            if (positions.Length == 0)
                return;
    
            foreach (var position in positions)
                Print("Buy at {0} SL {1}", position.EntryPrice, position.StopLoss);
    
            Stop();
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", 10, 10)
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
    
            if positions.Length == 0:
                return
    
            for position in positions:
                api.Print(f"Buy at {position.EntryPrice} SL {position.StopLoss}")
    
            api.Stop()            
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 시장 주문 실행: 10000 EURUSD 매수 (손절매: 10, 이익실현: 10)
    • 시장 주문 실행: 10000 EURUSD 매수 (손절매: 10, 이익실현: 10) 성공, 포지션 PID14579719
    • 매수 1.19087 손절매 null
    • 매수 1.19357 손절매 1.19257
    • cBot "New cBot"가 EURUSD, h1에서 중지됨.

비동기로 포지션 수정

아래 cBot은 시장 주문을 실행한 후 새로 열린 포지션을 수정합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.StopLoss == null)
        {
            double stopLoss = Symbol.Bid - 10 * Symbol.PipSize;
            ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.StopLoss is not None:
            return

        stopLoss = api.Symbol.Bid - 10 * api.Symbol.PipSize

        api.ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit)        

로그 출력

비동기로 포지션 닫기

다음 예제는 포지션이 존재하는 경우 비동기로 포지션을 닫는 방법을 보여줍니다.

Find() 메서드는 Positions 컬렉션에서 특정 라벨을 가진 포지션을 검색하는 데 사용됩니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, Symbol, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.GrossProfit > 10)
        {
            ClosePositionAsync(myPosition);
            Stop();
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.GrossProfit <= 10:
            return

        api.ClosePositionAsync(myPosition)
        api.Stop()        

로그 출력

비동기로 지정가 및 역지정가 주문 실행

위에서 언급한 바와 같이, 예약 주문 실행은 시장 주문 생성과 유사합니다.

그러나 이 두 메서드 간의 인수에는 약간의 차이가 있습니다. 시장 범위는 인수 목록에 없습니다. 또한 목표 가격을 지정해야 하며, 주문 만료 날짜를 지정하는 선택적 인수를 전달할 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, null, expiry);
        PlaceStopOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Ask + 10 * Symbol.PipSize, "myLabel", null, null, expiry);
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, None, expiry)
        api.PlaceStopOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask + 10 * api.Symbol.PipSize, "myLabel", None, None, expiry)    

로그 출력

비동기로 예약 주문 수정

다음 cBot은 비동기로 지정가 주문을 수정합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, 10, expiry);

    }
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel" && order.StopLoss == null)
                ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, null);
        }
    }
}
1
2
3
4
5
6
7
8
9
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, 10, expiry)

    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel" and order.StopLoss is None:
                api.ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, None)

로그 출력

비동기적으로 예약 주문 취소

  • 모든 예약 주문 취소

    아래 cBot은 현재 모든 예약 주문을 비동기적으로 취소합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                api.CancelPendingOrderAsync(order)
    

    로그 출력

    • EURUSD, h1에 대해 cBot "예약 주문 취소"가 성공적으로 시작되었습니다.
    • 예약 주문 OID274705 취소 중
    • 예약 주문 OID274706 취소 중
    • 예약 주문 OID274707 취소 중
    • 예약 주문 OID274708 취소 중
    • 예약 주문 OID274709 취소 중
    • 예약 주문 OID274705 취소 성공, PendingOrder OID274705
    • 예약 주문 OID274706 취소 성공, PendingOrder OID274706
    • 예약 주문 OID274707 취소 성공, PendingOrder OID274707
    • 예약 주문 OID274708 취소 성공, PendingOrder OID274708
    • 예약 주문 OID274709 취소 성공, PendingOrder OID274709
  • 특정 라벨이 있는 예약 주문 취소

    이 cBot은 특정 라벨이 있는 예약 주문만 취소합니다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                if (pendingOrder.Label == "myLabel")
                    CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    5
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                if order.Label == "myLabel":
                    api.CancelPendingOrderAsync(order)
    

비동기 메서드에 대한 콜백 함수

결과가 반환되면, 비동기 작업을 사용할 때 종종 실행을 제어해야 합니다. 이를 처리하기 위해 모든 비동기 메서드의 매개변수 목록 끝에 콜백 함수를 추가할 수 있습니다.

이 함수는 서버로부터 응답을 받는 즉시 호출됩니다. 예를 들어, 포지션이 열리거나 수정되거나 닫힐 때 호출될 수 있습니다.

  • 콜백이 있는 비동기 시장 주문

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, PositionOpened);
            if (operation.IsExecuting)
                Print(operation.ToString());
            else
                Print(operation.TradeResult.ToString());
    
        }
    
        private void PositionOpened(TradeResult tradeResult)
        {
            var position = tradeResult.Position;
            Print(tradeResult.ToString());
            if (tradeResult.IsSuccessful)
                Print("Position {0} opened at {1}", position.Id, position.EntryPrice);
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from System import Action
    
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, Action[TradeResult](self.on_position_opened))
    
            if (operation.IsExecuting)
                api.Print(operation.ToString())
            else
                api.Print(operation.TradeResult.ToString())
    
        def on_position_opened(self, tradeResult):
            position = tradeResult.Position
    
            api.Print(tradeResult.ToString())
    
            if tradeResult.IsSuccessful:
                api.Print(f"Position {position.Id} opened at {position.EntryPrice}")
    

    로그 출력

    • cBot "New cBot"가 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 시장 주문 실행 중
    • TradeOperation (10000 EURUSD 매수 시장 주문 실행 중 EXECUTING)
    • 10000 EURUSD 매수 시장 주문 실행 성공, Position PID14579835
    • TradeResult (성공, Position: PID14579835)
    • 포지션 14579835가 1.19414에 열림
  • 람다 표현식 사용

    이름이 있는 콜백 메서드를 정의하는 대신 람다 표현식을 사용할 수 있습니다.

    다음 예제에서는 주문이 실행될 때 결과 설명이 로그에 출력됩니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000,
                    Symbol.Ask - 20 * Symbol.PipSize, "myLabel", result => Print(result.ToString()));
        }
    }
    
    1
    2
    3
    4
    5
    from System import Action
    
    class Samples():
        def on_start(self):
            operation = api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask - 20 * api.Symbol.PipSize, "myLabel", Action[TradeResult](lambda result: api.Print(result.ToString())))
    

    로그 출력

    • cBot "새 cBot"이 EURUSD, h1에 대해 성공적으로 시작되었습니다.
    • 10000 EURUSD 매수 지정가 주문 실행 중 (가격: 1.19320)
    • 10000 EURUSD 매수 지정가 주문 실행 성공, PendingOrder OID25222083
    • TradeResult (성공, PendingOrder: OID25222083)

Image title