Position Management
StockSharp provides a flexible position management system that allows you to track the current state of positions, calculate them based on orders or trades, and maintain a lifecycle history (opening, closing, reversals).
PositionManager
The PositionManager class implements the IPositionManager interface and serves as the primary component for calculating current positions based on incoming messages.
Creating the Manager
The constructor accepts two parameters:
var state = new PositionManagerState();
var manager = new PositionManager(byOrders: false, state);
byOrders = true-- the position is calculated based on order balance changes. Suitable when the trading system receives order state updates but not individual trades.byOrders = false-- the position is calculated based on trade volumes (recommended mode). Provides more accurate accounting of executed operations.
Processing Messages
The ProcessMessage method accepts an incoming message (Message) and returns a PositionChangeMessage when the position changes, or null if the position has not changed:
var posChange = manager.ProcessMessage(executionMsg);
if (posChange != null)
{
Console.WriteLine($"Position: {posChange.CurrentValue}");
}
IPositionManagerState
The IPositionManagerState interface describes the internal state of the position manager. The PositionManagerState implementation stores information about current orders and positions.
Main Methods
| Method | Description |
|---|---|
AddOrGetOrder |
Registers a new order or returns an existing one by transactionId |
TryGetOrder |
Retrieves order parameters (instrument, portfolio, direction, balance) |
UpdateOrderBalance |
Updates the current order balance after partial execution |
RemoveOrder |
Removes a completed order from tracking |
UpdatePosition |
Updates the position by instrument and portfolio, returns the new value |
Clear |
Resets all manager state |
Working with State Example
var state = new PositionManagerState();
// Register an order
state.AddOrGetOrder(
transactionId: 12345,
securityId: secId,
portfolioName: "MyPortfolio",
side: Sides.Buy,
volume: 100,
balance: 100
);
// Update after partial execution
state.UpdateOrderBalance(12345, newBalance: 60);
// Update position directly
var newPosition = state.UpdatePosition(secId, "MyPortfolio", diff: 40);
Console.WriteLine($"Current position: {newPosition}");
// Clear
state.Clear();
PositionLifecycleTracker
The PositionLifecycleTracker class tracks the complete lifecycle of positions -- from opening to closing (round-trip). This is useful for analyzing individual trades, calculating profit for each position, and generating reports.
Key Features
- History: the
Historyproperty (IReadOnlyList<ReportPosition>) contains all completed round-trip positions. RoundTripClosedevent: fires when a position is closed (value reached zero) or reversed (position sign changed).ProcessPositionmethod: accepts a Position object and updates the internal state.
Detected States
| State | Description |
|---|---|
| Opening | Position transitions from zero to a non-zero value |
| Closing | Position value reaches zero |
| Reversal | Position sign changes (e.g., from long to short) |
Usage Example
var tracker = new PositionLifecycleTracker();
tracker.RoundTripClosed += report =>
{
Console.WriteLine($"Round-trip completed:");
Console.WriteLine($" Opened: {report.OpenTime}");
Console.WriteLine($" Closed: {report.CloseTime}");
};
// Process position updates
tracker.ProcessPosition(position);
// View history
foreach (var report in tracker.History)
{
Console.WriteLine($" {report.OpenTime} -> {report.CloseTime}");
}
PositionMessageAdapter
The PositionMessageAdapter class is a wrapper around a message adapter that automatically calculates positions from the message stream. It is used within the internal connector infrastructure.
How It Works
var innerAdapter = connector.Adapter;
var posManager = new PositionManager(byOrders: false, new PositionManagerState());
var posAdapter = new PositionMessageAdapter(innerAdapter, posManager);
The adapter intercepts order execution and trade messages, calls PositionManager.ProcessMessage, and generates corresponding PositionChangeMessage instances for upstream handlers.
Positions in Strategies
In the Strategy class, the current position is accessed through the Position property:
// Current position for the primary instrument
decimal currentPosition = Position;
// Close position
if (Position > 0)
SellMarket(Math.Abs(Position));
else if (Position < 0)
BuyMarket(Math.Abs(Position));
// Or through a built-in method
ClosePosition();
For more details about trading operations in strategies, see the Trading Operations section.