Trading data and events
The trading entities of the chart, the instrument, the portfolio, the position, the orders and the trades, are available to every chart indicator through TradingManager, and the indicator can override the handlers of their changes. A chart strategy adds its own position and the order methods on top of this (see Overview and lifecycle).
Trading data
TradingManager returns an ITradingManager
and can be null, so check it before use. Its properties:
Security: the selected instrument, a Security;Portfolio: the selected portfolio, a Portfolio;Position: the current position, a Position;MyTrades: the executed trades, MyTrade objects;Orders: the placed orders, Order objects.
Events
Override these methods to receive the updates:
- OnNewOrder(order): a new order;
- OnOrderChanged(order): an order changed;
- OnNewMyTrade(myTrade): a new trade;
- OnPositionChanged(position): the position changed;
- OnPortfolioChanged(portfolio): every update of the selected portfolio (balance, PnL, margin: on each tick while a position is open), not only a change of the selection. Keep the handler cheap;
- OnPortfolioSelected(portfolio): another portfolio was selected on the chart. Raised on the selection only, so this is where per-account work belongs: reloading an option chain, re-requesting trading data, resetting per-account state;
- OnOrderRegisterFailed(order, message), OnOrderCancelFailed(order, message), OnOrderModifyFailed(order, newOrder, error): an attempt to place, cancel or modify an order failed.
The handlers receive every order and trade of the chart instrument and portfolio, including the ones placed by hand, not only the ones of your strategy.
The two portfolio methods are not interchangeable: OnPortfolioChanged fires many times per second while a position
is open, so reloading data there produces a request storm; OnPortfolioSelected fires once per account switch.
protected override void OnPortfolioSelected(Portfolio portfolio)
{
// Raised once per account switch: the place for per-account work
this.LogInfo($"Selected portfolio: {portfolio}");
}
protected override void OnPortfolioChanged(Portfolio portfolio)
{
// Raised on every balance or PnL update: no logging here, only refresh the displayed values
RedrawChart();
}
Example
The indicator below draws the portfolio, the position, the active orders and the trades on the chart, logs the new
orders, order changes, trades, failures and the portfolio selection, and only redraws the chart in
OnPortfolioChanged and OnPositionChanged:
using System.Drawing;
using System.Linq;
using System.Text;
using ATAS.DataFeedsCore;
using ATAS.Indicators;
using OFT.Rendering.Context;
using OFT.Rendering.Tools;
using Utils.Common.Logging;
namespace ATAS.Docs.Samples.ChartStrategies;
public class TradingInfoIndicator : Indicator
{
private readonly RenderFont _font = new("Arial", 10);
public TradingInfoIndicator()
{
EnableCustomDrawing = true;
SubscribeToDrawingEvents(DrawingLayouts.Final);
}
protected override void OnCalculate(int bar, decimal value)
{
}
protected override void OnNewOrder(Order order)
{
this.LogInfo($"New order: {order}");
}
protected override void OnOrderChanged(Order order)
{
this.LogInfo($"Order changed: {order}");
}
protected override void OnNewMyTrade(MyTrade myTrade)
{
this.LogInfo($"New trade: {myTrade}");
}
protected override void OnOrderRegisterFailed(Order order, string message)
{
this.LogWarn($"Order {order} was not registered: {message}");
}
protected override void OnOrderCancelFailed(Order order, string message)
{
this.LogWarn($"Order {order} was not cancelled: {message}");
}
protected override void OnOrderModifyFailed(Order order, Order newOrder, string error)
{
this.LogWarn($"Order {order} was not modified: {error}");
}
protected override void OnPortfolioSelected(Portfolio portfolio)
{
// Raised once per account switch: the place for per-account work
this.LogInfo($"Selected portfolio: {portfolio}");
}
protected override void OnPortfolioChanged(Portfolio portfolio)
{
// Raised on every balance or PnL update: no logging here, only refresh the displayed values
RedrawChart();
}
protected override void OnPositionChanged(Position position)
{
RedrawChart();
}
protected override void OnRender(RenderContext context, DrawingLayouts layout)
{
var tradingManager = TradingManager;
if (tradingManager == null)
return;
var label = new StringBuilder();
if (tradingManager.Security != null)
label.AppendLine($"Security: {tradingManager.Security}");
if (tradingManager.Portfolio != null)
label.AppendLine($"Portfolio: {tradingManager.Portfolio}");
if (tradingManager.Position != null)
label.AppendLine($"Position: {tradingManager.Position}");
var orders = tradingManager.Orders
.Where(t => t.State == OrderStates.Active)
.ToList();
if (orders.Count > 0)
{
label.AppendLine();
label.AppendLine("---------------------Active orders:------------------------");
foreach (var order in orders)
label.AppendLine(order.ToString());
}
var myTrades = tradingManager.MyTrades.ToList();
if (myTrades.Count > 0)
{
label.AppendLine();
label.AppendLine("---------------------MyTrades:------------------------");
foreach (var myTrade in myTrades)
label.AppendLine(myTrade.ToString());
}
if (label.Length == 0)
return;
var text = label.ToString();
var size = context.MeasureString(text, _font);
context.FillRectangle(Color.DarkRed, new Rectangle(25, 25, size.Width + 50, size.Height + 50));
context.DrawString(text, _font, Color.Azure, 50, 50);
}
}

Trading statistics
TradingStatisticsProvider (check it for null) gives the
trading statistics of the platform as ITradingStatistics
objects:
- RawStatistics: all orders, own
trades and closed trades of the platform, without any filter. Use it for the
Orders,MyTrades,HistoryMyTradesandDailyNotescollections;EquityandStatisticsare not available in it. - FilteredStatistics: the
statistics filtered by the period, accounts, instruments and playbooks selected in the statistics window of the
platform, with the calculated
EquityandStatisticscollections. The filter is in theFrom,To,Accounts,SecuritiesandPlaybooksproperties of the provider; changing them from an indicator changes the filter of the statistics window too.
The collections of an ITradingStatistics: Orders (Order), MyTrades
(MyTrade), HistoryMyTrades (the closed trades,
HistoryMyTrade), DailyNotes (DailyNote),
Equity (EquityValue) and Statistics
(IStatisticsParameterGroup). Each one can be
enumerated and raises Added, Changed, Removed and Cleared.
The provider replaces these objects when the statistics source changes (for example, when a Replay connection is
started or stopped) and raises RawStatisticsSourceChanged
and FilteredStatisticsSourceChanged
with the new object: unsubscribe from the old one and subscribe to the new one, do not keep the old reference. After
the statistics are rebuilt or cleared, StatisticsRebuilt
is raised. The Realtime and Replay properties and LoadHistoryAsync of the provider are obsolete.
The indicator below logs the closed trades of the account and instrument of the chart and every new closed trade:
using System;
using System.Linq;
using ATAS.DataFeedsCore;
using ATAS.DataFeedsCore.Statistics;
using ATAS.Indicators;
using Utils.Common.Logging;
namespace ATAS.Docs.Samples.ChartStrategies;
public class ClosedTradesStatisticsIndicator : Indicator
{
private ITradingStatistics? _statistics;
protected override void OnCalculate(int bar, decimal value)
{
}
protected override void OnInitialize()
{
if (TradingStatisticsProvider is null)
return;
TradingStatisticsProvider.RawStatisticsSourceChanged += OnStatisticsSourceChanged;
TradingStatisticsProvider.StatisticsRebuilt += LogClosedTrades;
SetStatistics(TradingStatisticsProvider.RawStatistics);
}
protected override void OnDispose()
{
if (TradingStatisticsProvider != null)
{
TradingStatisticsProvider.RawStatisticsSourceChanged -= OnStatisticsSourceChanged;
TradingStatisticsProvider.StatisticsRebuilt -= LogClosedTrades;
}
SetStatistics(null);
}
private void OnStatisticsSourceChanged(ITradingStatistics statistics)
{
SetStatistics(statistics);
}
private void SetStatistics(ITradingStatistics? statistics)
{
if (_statistics != null)
_statistics.HistoryMyTrades.Added -= OnClosedTradeAdded;
_statistics = statistics;
if (_statistics == null)
return;
_statistics.HistoryMyTrades.Added += OnClosedTradeAdded;
LogClosedTrades();
}
private void LogClosedTrades()
{
var trades = _statistics?.HistoryMyTrades
.Where(IsChartTrade)
.ToList();
if (trades != null)
this.LogInfo($"Closed trades: {trades.Count}, total PnL: {trades.Sum(t => t.PnL)}");
}
private void OnClosedTradeAdded(HistoryMyTrade trade)
{
if (IsChartTrade(trade))
this.LogInfo($"New closed trade: {trade.OpenTime} - {trade.CloseTime}, PnL: {trade.PnL}");
}
// Only the trades of the account and instrument selected on the chart
private bool IsChartTrade(HistoryMyTrade trade)
{
var portfolio = TradingManager?.Portfolio;
var security = TradingManager?.Security;
return portfolio != null
&& security != null
&& trade.AccountID == portfolio.AccountID
&& string.Equals(trade.SecurityId, security.SecurityId, StringComparison.InvariantCultureIgnoreCase);
}
}