@@ -19,6 +19,7 @@ public class StrategyPositionManager(Func<string> strategyIdGetter)
1919 private readonly SyncObject _lock = new ( ) ;
2020 private readonly Dictionary < ( SecurityId secId , Portfolio pf ) , Position > _positions = [ ] ;
2121 private readonly Dictionary < Order , OrderExecInfo > _orderExecInfos = [ ] ;
22+ private readonly Dictionary < SecurityId , decimal > _lastPrices = [ ] ;
2223
2324 /// <summary>
2425 /// Per-position aggregates cache (blocked volume and active orders counters).
@@ -127,6 +128,7 @@ public void Reset()
127128 _orderExecInfos . Clear ( ) ;
128129 _posAggs . Clear ( ) ;
129130 _orderTracks . Clear ( ) ;
131+ _lastPrices . Clear ( ) ;
130132 }
131133 }
132134
@@ -141,7 +143,7 @@ private void UpdateAggregates(Order order, Position position)
141143 var agg = _posAggs . SafeAdd ( ( order . Security . ToSecurityId ( ) , order . Portfolio ) , _ => new ( ) ) ;
142144
143145 var balance = order . Balance ; // non-nullable balance
144- var newActive = ! order . State . IsFinal ( ) && balance > 0 ;
146+ var newActive = order . State == OrderStates . Active && balance > 0 ;
145147
146148 if ( ! _orderTracks . TryGetValue ( order , out var track ) )
147149 {
@@ -212,7 +214,8 @@ private void UpdateAggregates(Order order, Position position)
212214 }
213215
214216 var blockedNet = agg . BlockedBuy - agg . BlockedSell ;
215- position . BlockedValue = blockedNet == 0 ? null : blockedNet ;
217+ var hasActiveOrders = ( agg . BuyCount + agg . SellCount ) > 0 ;
218+ position . BlockedValue = hasActiveOrders ? blockedNet : ( position . BlockedValue is null ? null : 0m ) ;
216219 position . BuyOrdersCount = agg . BuyCount == 0 ? null : agg . BuyCount ;
217220 position . SellOrdersCount = agg . SellCount == 0 ? null : agg . SellCount ;
218221 }
@@ -225,6 +228,12 @@ public void ProcessOrder(Order order)
225228 {
226229 ArgumentNullException . ThrowIfNull ( order ) ;
227230
231+ if ( order . Balance < 0 )
232+ throw new ArgumentException ( LocalizedStrings . OrderBalanceNotEnough . Put ( order . TransactionId , order . Balance ) , nameof ( order ) ) ;
233+
234+ if ( order . State is OrderStates . None or OrderStates . Pending or OrderStates . Failed )
235+ return ; // not yet active
236+
228237 var matchedAbs = order . GetMatchedVolume ( ) ?? 0m ; // cumulative executed volume (absolute)
229238 var signSide = order . Side == Sides . Sell ? - 1 : 1 ;
230239
@@ -236,9 +245,16 @@ public void ProcessOrder(Order order)
236245
237246 lock ( _lock )
238247 {
248+ var key = ( order . Security . ToSecurityId ( ) , order . Portfolio ) ;
249+ var posExists = _positions . ContainsKey ( key ) ;
250+
251+ // If there are no executions yet and the order state is not Active and no position exists yet, ignore.
252+ if ( matchedAbs == 0 && order . State != OrderStates . Active && ! posExists )
253+ return ;
254+
239255 position = GetOrCreate ( order . Security , order . Portfolio , out isNew ) ;
240256
241- // ensure aggregates reflect current order state before fill handling
257+ // ensure aggregates reflect current order state before fill handling (to close blocked on Done, etc.)
242258 UpdateAggregates ( order , position ) ;
243259
244260 if ( ! _orderExecInfos . TryGetValue ( order , out var execInfo ) )
@@ -294,6 +310,17 @@ public void ProcessOrder(Order order)
294310 if ( deltaCommission != 0 )
295311 position . Commission = posCommission + deltaCommission ;
296312
313+ // Recompute position market value if we know last price for this security
314+ if ( _lastPrices . TryGetValue ( order . Security . ToSecurityId ( ) , out var lastPrice ) )
315+ {
316+ var value = newQty . Abs ( ) * lastPrice ;
317+ position . CurrentPrice = value == 0 ? 0m : value ;
318+ }
319+ else
320+ {
321+ position . CurrentPrice = null ; // unknown market price
322+ }
323+
297324 position . LocalTime = order . LocalTime ;
298325 position . LastChangeTime = order . ServerTime ;
299326 }
@@ -318,12 +345,15 @@ public void UpdateCurrentPrice(SecurityId secId, decimal price, DateTimeOffset s
318345
319346 lock ( _lock )
320347 {
348+ _lastPrices [ secId ] = price ;
349+
321350 foreach ( var ( ( kSecId , _) , pos ) in _positions )
322351 {
323352 if ( ! kSecId . Equals ( secId ) )
324353 continue ;
325354
326- pos . CurrentPrice = price ;
355+ var qty = pos . CurrentValue ?? 0m ;
356+ pos . CurrentPrice = qty == 0 ? 0m : qty . Abs ( ) * price ;
327357 pos . LastChangeTime = serverTime ;
328358 pos . LocalTime = localTime ;
329359 ( changed ??= [ ] ) . Add ( pos ) ;
0 commit comments