ATAS
Loading...
Searching...
No Matches
Managing orders in trading

The main methods for managing orders include methods such as OpenOrder, ModifyOrder, CancelOrder. By calling these methods, developers are essentially providing execution instructions. However, the exchange / trading connection does not guarantee that this instruction will be followed. They can be fulfilled completely, partially or with deviations.

To obtain information about what is happening with orders, developers can override methods such as OnOrderChanged, OnOrderRegisterFailed, OnOrderModifyFailed, OnOrderCancelFailed.

It is important to understand that these methods cause less response from the exchange/trading connection and may be on different threads and may sometimes use sync methods.

Using synchronous methods

Order placing

To place an order, use the OpenOrder method, to which the filled Order entity is passed.

An example of placing a market buy order with a volume of 1 lot:

var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Buy,
Type = OrderTypes.Market,
QuantityToFill = 1,
};
OpenOrder(order);

An example of placing a limit order to sell at a price of 100 with a volume of 1 lot:

var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.Limit,
Price = 100,
QuantityToFill = 1,
};
OpenOrder(order);

An example of placing a stop order to sell at a price of 100 with a volume of 1 lot:

var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.Stop,
TriggerPrice = 100,
QuantityToFill = 1,
};
OpenOrder(order);

An example of placing a stop-limit order to sell at an activation price of 100 and a maximum execution price of 95, with a volume of 1 lot:

var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.StopLimit,
TriggerPrice = 100,
Price = 95,
QuantityToFill = 1,
};
OpenOrder(order);

The OpenOrder method does not guarantee that an order will be placed, it only sends the order to the exchange. The sending result should be viewed in the OnOrderChanged and OnOrderRegisterFailed methods.

If the exchange rejects the application for placing an order, the OnOrderRegisterFailed method will be called, which will receive a link to the original placed order and a message from the exchange.

In the process of placing an order and accepting it by the exchange, the exchange sends updates to this order. All order updates are sent to OnOrderChanged. Through order.Status() you can get the current state of the order.

An example of placing an order and controlling its placement:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
_firstTime = false;
_order = new Order
{
Direction = OrderDirections.Buy,
Type = OrderTypes.Limit,
Price = 100,
QuantityToFill = 1,
};
OpenOrder(_order);
}
}
protected override void OnOrderRegisterFailed(Order order, string message)
{
if (order == _order)
{
// order placement error, see message for details.
}
}
protected override void OnOrderChanged(Order order)
{
if (order == _order)
{
switch (order.Status())
{
case OrderStatus.None:
// The order has an undefined status (you need to wait for the next method calls).
break;
case OrderStatus.Placed:
// the order is placed.
break;
case OrderStatus.Filled:
// the order is filled.
break;
case OrderStatus.PartlyFilled:
// the order is partially filled.
{
var unfilled = order.Unfilled; // this is a unfilled volume.
break;
}
case OrderStatus.Canceled:
// the order is canceled.
break;
}
}
}
}
Represents an order for trading on a financial exchange.
Definition Order.cs:15
decimal Unfilled
Gets the remaining unfilled volume of the order.
Definition Order.cs:318
Represents a portfolio entity with various properties related to account balance, Profit and Loss (Pn...
Definition Portfolio.cs:20
Represents a security entity used in the application.
Definition Security.cs:16
Represents an abstract class for a chart strategy that extends the functionality of an Indicator and ...
Definition ChartStrategy.cs:27
Definition AsyncConnector.cs:2
OrderTypes
Specifies the type of an order.
Definition OrderTypes.cs:7
OrderStatus
Represents the possible status of an order.
Definition OrderStates.cs:33
OrderDirections
Specifies the direction of an order.
Definition OrderDirections.cs:7
Definition ChartStrategy.cs:2

Order changing

To change an placed order, you need to create a copy of this order, change the price or volume in it and call ModifyOrder, passing the old order and the new one as parameters. We also need to remember that if we store a link to the old order, then when modifying we need to assign our field a link to the new order.

If the OnOrderModifyFailed method receives an order previously sent for modification, then the modification was impossible for some reason.

The order change status should be tracked in OnOrderChanged.

In the example of changing an order, it is assumed that the _order object contains an order that is active at the time of launch:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private Order _newOrder;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
// Here we receive a signal and open an order.
// Here the conditions under which you need to change the order price have been met.
_newOrder = _order.Clone();
_newOrder.Price = 200;
ModifyOrder(_order, _newOrder);
}
}
protected override void OnOrderModifyFailed(Order order, Order newOrder, string error)
{
if (order == _order)
{
// Here it will be clear that it was not possible to change _order.
}
}
protected override void OnOrderChanged(Order order)
{
if (order == _newOrder)
{
switch (order.Status())
{
case OrderStatus.None:
// The order has an undefined status (you need to wait for the next method calls).
break;
case OrderStatus.Placed:
// the new order has been placed, the change was successful.
break;
case OrderStatus.Filled:
// the order was placed and filled.
break;
case OrderStatus.PartlyFilled:
// the order is partially filled.
{
var unfilled = order.Unfilled; // this is a unfilled volume.
break;
}
case OrderStatus.Canceled:
// the order is canceled.
break;
}
}
}
}
Order Clone()
Creates a shallow copy of the current order.
Definition Order.cs:637

Order canceling

CancelOrder sends an instruction to the exchange to cancel the order. There is also no guarantee of successful cancellation, so you need to track the status of orders in the OnOrderCancelFailed and OnOrderChanged methods.

Before sending a CancelOrder, it is recommended to ensure that the State of the order is equal to OrderStates.Active.

In the order cancellation example, it is assumed that the _order object contains an order that is active at the time of launch:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
// Here the conditions under which we need to cancel our order have been met.
if (_order.State == OrderStates.Active)
{
CancelOrder(_order);
_firstTime = false;
}
}
}
protected override void OnOrderCancelFailed(Order order, string message)
{
if (order == _order)
{
// Here it will be clear that cancel _order did not work.
}
}
protected override void OnOrderChanged(Order order)
{
if (order == _order && order.Status() == OrderStatus.Canceled)
{
// Here it will be clear that the _order was successfully canceled.
}
}
}
OrderStates State
Gets or sets the current state of the order.
Definition Order.cs:504
bool Canceled
Gets a value indicating whether the order is canceled.
Definition Order.cs:572
OrderStates
Represents the possible states of an order.
Definition OrderStates.cs:7

Using asynchronous methods

You can use asynchronous order management methods just like synchronous ones, and getting the results becomes more convenient.

Now there is no need to track the result in the OnNewOrder, OnOrderChanged, OnOrderRegisterFailed, OnOrderModifyFailed and OnOrderCancelFailed methods. Opening, canceling or modifying an order must be placed in a try-catch block.

It must be remembered that the result can still be both successful and unsuccessful. If the result was successful, in the code below we can find out the status of the order or perform other necessary actions. If the result is unsuccessful, an exception is thrown and we can intercept it in the catch block.

It should also be noted that if you have active limit or stop limit orders, the moment when their state or status changes can be found in OnOrderChanged.

Order placing

Using OpenOrderAsync:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
_firstTime = false;
_order = new Order
{
Direction = OrderDirections.Buy,
Type = OrderTypes.Limit,
Price = 100,
QuantityToFill = 1,
};
OpenPositionAsync(_order);
}
}
private async Task OpenPositionAsync(Order order)
{
try
{
await OpenOrderAsync(order);
// If there was no error and the order was placed, below we can track the positive result of placing the order.
switch (order.Status())
{
case OrderStatus.Placed:
// the order is placed.
break;
case OrderStatus.Filled:
// the order is filled.
break;
case OrderStatus.PartlyFilled:
// the order is partially filled.
var unfilled = order.Unfilled; // this is an unfilled volume.
break;
}
}
catch (Exception ex)
{
// Here we find out that the order could not be opened.
// As an option, we will output an error message to the log.
this.LogInfo($"Open position error: {ex.Message}.");
}
}
}

Order changing

Using ModifyOrderAsync:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private Order _newOrder;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
// Here we receive a signal and open an order.
// Here the conditions under which you need to change the order price have been met.
ChangeOrderAsync();
}
}
private async Task ChangeOrderAsync()
{
_newOrder = _order.Clone();
_newOrder.Price = 200;
try
{
await ModifyOrderAsync(_order, _newOrder);
// Here we find out that the order changes were successful.
}
catch (Exception ex)
{
// Here we find out that the order could not be changed.
}
}
}

Order canceling

Using CancelOrderAsync:

public class SampleStrategy : ChartStrategy
{
private Order _order;
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
// Here the conditions under which we need to cancel our order have been met.
if (_order.State == OrderStates.Active)
{
TryCancelOrderAsync();
_firstTime = false;
}
}
}
private async Task TryCancelOrderAsync()
{
try
{
await CancelOrderAsync(_order);
// Here we know that the order was canceled successfully.
}
catch (Exception ex)
{
// Here we find out that the order could not be canceled.
}
}
}

Points to consider

Since the API provides an asynchronous mechanism for working with trading functions, this must be taken into account during development.

Some common mistakes when working with an asynchronous approach:

  • In the strategy, a trigger to cancel an order is triggered, and the algorithm calls CancelOrder. While the response has not arrived from the exchange, the trigger fires again and the algorithm again sends the CancelOrder request to the exchange. As a result, the second request will be rejected by the exchange.
  • The strategy fires a trigger to open a position, the algorithm checks CurrentPosition, which is equal to zero, and sends a market order. While the response has not come from the exchange and the value of the position has not been updated, the trigger fires again and another market order is sent, which ultimately leads to an increase in risks.
  • In the strategy, a trigger to close a position is triggered, the algorithm checks CurrentPosition, creates a closing order with a volume equal to CurrentPositions, and sends this order. While the response has not come from the exchange and the value of the position has not been updated, the trigger fires again and another market order is sent, which ultimately leads not to the closing of the position, but to its reversal. It is important to understand that order statuses and positions arrive asynchronously as a response is received from the exchange.