public Tuple <Trade, bool> ProcessTradeMessage(Security security, ExecutionMessage message) { if (security == null) { throw new ArgumentNullException("security"); } if (message == null) { throw new ArgumentNullException("message"); } var trade = GetTrade(security, message.TradeId, message.TradeStringId, (id, stringId) => { var t = message.ToTrade(EntityFactory.CreateTrade(security, id, stringId)); t.LocalTime = message.LocalTime; t.Time = message.ServerTime; message.CopyExtensionInfo(t); return(t); }); return(trade); }
public Tuple <OrderFail, bool> ProcessOrderFailMessage(Security security, ExecutionMessage message) { if (security == null) { throw new ArgumentNullException("security"); } if (message == null) { throw new ArgumentNullException("message"); } var data = _cache.GetData(security); Order order = null; if (!message.OrderStringId.IsEmpty()) { order = data.OrdersByStringId.TryGetValue(message.OrderStringId); } bool isCancelled; if (order == null) { if (message.OriginalTransactionId == 0) { throw new ArgumentOutOfRangeException("message", message.OriginalTransactionId, LocalizedStrings.Str715); } var orders = data.Orders; order = (Order)orders.TryGetValue(CreateOrderKey(message.OrderType, message.OriginalTransactionId, true)); if (order != null && order.Id == message.OrderId) { isCancelled = true; } else { order = (Order)orders.TryGetValue(CreateOrderKey(message.OrderType, message.OriginalTransactionId, false)); isCancelled = false; } if (order == null) { return(null); } } else { var pair = data.Orders.LastOrDefault(p => p.Value.Order == order); isCancelled = pair.Key.Item3; } // ServerTime для заявки - это время регистрации order.LastChangeTime = message.LocalTime; order.LocalTime = message.LocalTime; if (message.OrderStatus != null) { order.Status = message.OrderStatus; } //для ошибок снятия не надо менять состояние заявки if (!isCancelled) { order.State = OrderStates.Failed; } if (message.Commission != null) { order.Commission = message.Commission; } message.CopyExtensionInfo(order); var error = message.Error ?? new InvalidOperationException( isCancelled ? LocalizedStrings.Str716 : LocalizedStrings.Str717); var fail = EntityFactory.CreateOrderFail(order, error); fail.ServerTime = message.ServerTime; fail.LocalTime = message.LocalTime; return(Tuple.Create(fail, isCancelled)); }
public Tuple <MyTrade, bool> ProcessMyTradeMessage(Security security, ExecutionMessage message) { if (security == null) { throw new ArgumentNullException("security"); } if (message == null) { throw new ArgumentNullException("message"); } var originalTransactionId = _orderStatusTransactions.Contains(message.OriginalTransactionId) ? 0 : message.OriginalTransactionId; if (originalTransactionId == 0 && message.OrderId == null && message.OrderStringId.IsEmpty()) { throw new ArgumentOutOfRangeException("message", originalTransactionId, LocalizedStrings.Str715); } var securityData = _cache.GetData(security); var myTrade = securityData.MyTrades.TryGetValue(Tuple.Create(originalTransactionId, message.TradeId ?? 0)); if (myTrade != null) { return(Tuple.Create(myTrade, false)); } var order = GetOrder(security, originalTransactionId, message.OrderId, message.OrderStringId); if (order == null) { return(null); } var trade = message.ToTrade(EntityFactory.CreateTrade(security, message.TradeId, message.TradeStringId)); var isNew = false; myTrade = securityData.MyTrades.SafeAdd(Tuple.Create(order.TransactionId, trade.Id), key => { isNew = true; var t = EntityFactory.CreateMyTrade(order, trade); if (t.ExtensionInfo == null) { t.ExtensionInfo = new Dictionary <object, object>(); } if (message.Commission != null) { t.Commission = message.Commission; } if (message.Slippage != null) { t.Slippage = message.Slippage; } message.CopyExtensionInfo(t); //trades.Add(t); _cache.MyTrades.Add(t); return(t); }); return(Tuple.Create(myTrade, isNew)); // mika // http://stocksharp.com/forum/yaf_postst1072_Probliemy-so-sdielkami--pozitsiiami.aspx // из-за того, что сделки по заявке иногда приходит быстрее события NewOrders, неправильно расчитывается поза по стратегиям //var raiseOrderChanged = false; //trades.SyncDo(d => //{ // var newBalance = order.Volume - d.Sum(t => t.Trade.Volume); // if (order.Balance > newBalance) // { // raiseOrderChanged = true; // order.Balance = newBalance; // if (order.Balance == 0) // order.State = OrderStates.Done; // } //}); //if (raiseOrderChanged) // RaiseOrderChanged(order); }
public OrderChangeInfo ApplyChanges(ExecutionMessage message, bool isCancel) { var order = Order; OrderChangeInfo retVal; if (order.State == OrderStates.Done) { // данные о заявке могут приходить из маркет-дата и транзакционного адаптеров retVal = OrderChangeInfo.Create(order, _raiseNewOrder, false); _raiseNewOrder = false; return(retVal); //throw new InvalidOperationException("Изменение заявки в состоянии Done невозможно."); } else if (order.State == OrderStates.Failed) { // some adapters can resend order's info //throw new InvalidOperationException(); return(null); } var isPending = order.State == OrderStates.Pending; if (message.OrderId != null) { order.Id = message.OrderId.Value; } if (!message.OrderStringId.IsEmpty()) { order.StringId = message.OrderStringId; } if (!message.OrderBoardId.IsEmpty()) { order.BoardId = message.OrderBoardId; } //// некоторые коннекторы не транслируют при отмене отмененный объем //// esper. при перерегистрации заявок необходимо обновлять баланс //if (message.Balance > 0 || !isCancelled || isReRegisterCancelled) //{ // // BTCE коннектор не транслирует баланс заявки // if (!(message.OrderState == OrderStates.Active && message.Balance == 0)) // order.Balance = message.Balance; //} if (message.Balance != null) { order.Balance = message.Balance.Value; } // IB коннектор не транслирует состояние заявки в одном из своих сообщений if (message.OrderState != null) { order.State = order.State.CheckModification(message.OrderState.Value); } if (order.Time == DateTimeOffset.MinValue) { order.Time = message.ServerTime; } // для новых заявок используем серверное время, // т.к. заявка получена первый раз и не менялась // ServerTime для заявки - это время регистрации order.LastChangeTime = _raiseNewOrder ? message.ServerTime : message.LocalTime; order.LocalTime = message.LocalTime; //нулевой объем может быть при перерегистрации if (order.Volume == 0 && message.OrderVolume != null) { order.Volume = message.OrderVolume.Value; } if (message.Commission != null) { order.Commission = message.Commission; } if (!message.CommissionCurrency.IsEmpty()) { order.CommissionCurrency = message.CommissionCurrency; } if (message.TimeInForce != null) { order.TimeInForce = message.TimeInForce.Value; } if (message.Latency != null) { if (isCancel) { order.LatencyCancellation = message.Latency.Value; } else if (isPending) { if (order.State != OrderStates.Pending) { order.LatencyRegistration = message.Latency.Value; } } } if (message.AveragePrice != null) { order.AveragePrice = message.AveragePrice; } if (message.Yield != null) { order.Yield = message.Yield; } message.CopyExtensionInfo(order); retVal = OrderChangeInfo.Create(order, _raiseNewOrder, true); _raiseNewOrder = false; return(retVal); }
public Tuple <Order, bool, bool> ProcessOrderMessage(Security security, ExecutionMessage message) { if (security == null) { throw new ArgumentNullException("security"); } if (message == null) { throw new ArgumentNullException("message"); } if (message.Error != null) { throw new ArgumentException(LocalizedStrings.Str714Params.PutEx(message)); } bool isNew; var transactionId = message.TransactionId; if (transactionId == 0) { // ExecMsg.OriginalTransactionId == OrderStatMsg.TransactionId when orders info requested by OrderStatMsg transactionId = _orderStatusTransactions.Contains(message.OriginalTransactionId) ? 0 : message.OriginalTransactionId; } var securityData = _cache.GetData(security); var orderInfo = GetOrderInfo(securityData, message.OrderType, transactionId, message.OrderId, message.OrderStringId, trId => { var o = EntityFactory.CreateOrder(security, message.OrderType, trId); o.Time = message.ServerTime; o.Price = message.Price; o.Volume = message.Volume ?? 0; o.Direction = message.Side; o.Comment = message.Comment; o.ExpiryDate = message.ExpiryDate; o.Condition = message.Condition; o.UserOrderId = message.UserOrderId; o.Portfolio = message.PortfolioName.IsEmpty() ? _portfolios.FirstOrDefault().Value : ProcessPortfolio(message.PortfolioName).Item1; return(o); }, out isNew, true); var order = orderInfo.Item1; var isCancelled = orderInfo.Item2; //var isReReregisterCancelled = orderInfo.Item3; var raiseNewOrder = orderInfo.Item3; var isPending = order.State == OrderStates.Pending; //var isPrevIdSet = (order.Id != null || !order.StringId.IsEmpty()); bool isChanged; if (order.State == OrderStates.Done) { // данные о заявке могут приходить из маркет-дата и транзакционного адаптеров isChanged = false; //throw new InvalidOperationException("Изменение заявки в состоянии Done невозможно."); } else { if (message.OrderId != null) { order.Id = message.OrderId.Value; } if (!message.OrderStringId.IsEmpty()) { order.StringId = message.OrderStringId; } if (!message.OrderBoardId.IsEmpty()) { order.BoardId = message.OrderBoardId; } //// некоторые коннекторы не транслируют при отмене отмененный объем //// esper. при перерегистрации заявок необходимо обновлять баланс //if (message.Balance > 0 || !isCancelled || isReReregisterCancelled) //{ // // BTCE коннектор не транслирует баланс заявки // if (!(message.OrderState == OrderStates.Active && message.Balance == 0)) // order.Balance = message.Balance; //} if (message.Balance != null) { order.Balance = message.Balance.Value; } // IB коннектор не транслирует состояние заявки в одном из своих сообщений if (message.OrderState != null) { order.State = message.OrderState.Value; } if (order.Time == DateTimeOffset.MinValue) { order.Time = message.ServerTime; } // для новых заявок используем серверное время, // т.к. заявка получена первый раз и не менялась // ServerTime для заявки - это время регистрации order.LastChangeTime = isNew ? message.ServerTime : message.LocalTime; order.LocalTime = message.LocalTime; //нулевой объем может быть при перерегистрации if (order.Volume == 0 && message.Volume != null) { order.Volume = message.Volume.Value; } if (message.Commission != null) { order.Commission = message.Commission; } if (message.TimeInForce != null) { order.TimeInForce = message.TimeInForce.Value; } if (isPending) { if (order.State != OrderStates.Pending && message.Latency != null) { order.LatencyRegistration = message.Latency.Value; } } else if (isCancelled && order.State == OrderStates.Done) { if (message.Latency != null) { order.LatencyCancellation = message.Latency.Value; } } isChanged = true; } //if (isNew || (!isPrevIdSet && (order.Id != null || !order.StringId.IsEmpty()))) //{ // так как биржевые идентифиаторы могут повторяться, то переписываем старые заявки новыми как наиболее актуальными if (order.Id != null) { securityData.OrdersById[order.Id.Value] = order; _cache.AllOrdersById[order.Id.Value] = order; } if (!order.StringId.IsEmpty()) { securityData.OrdersByStringId[order.StringId] = order; _cache.AllOrdersByStringId[order.StringId] = order; } //} //if (message.OrderType == OrderTypes.Conditional && (message.DerivedOrderId != null || !message.DerivedOrderStringId.IsEmpty())) //{ // var derivedOrder = GetOrder(security, 0L, message.DerivedOrderId ?? 0, message.DerivedOrderStringId); // if (order == null) // _orderStopOrderAssociations.Add(Tuple.Create(message.DerivedOrderId ?? 0, message.DerivedOrderStringId), new RefPair<Order, Action<Order, Order>>(order, (s, o) => s.DerivedOrder = o)); // else // order.DerivedOrder = derivedOrder; //} message.CopyExtensionInfo(order); return(Tuple.Create(order, raiseNewOrder, isChanged)); }
public Tuple <MyTrade, bool> ProcessMyTradeMessage(Order order, Security security, ExecutionMessage message, long transactionId) { if (security == null) { throw new ArgumentNullException(nameof(security)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } var securityData = GetData(security); if (transactionId == 0 && message.OrderId == null && message.OrderStringId.IsEmpty()) { throw new ArgumentOutOfRangeException(nameof(message), transactionId, LocalizedStrings.Str715); } var myTrade = securityData.MyTrades.TryGetValue(Tuple.Create(transactionId, message.TradeId ?? 0)); if (myTrade != null) { return(Tuple.Create(myTrade, false)); } if (order == null) { order = GetOrder(security, transactionId, message.OrderId, message.OrderStringId); if (order == null) { return(null); } } var trade = message.ToTrade(EntityFactory.CreateTrade(security, message.TradeId, message.TradeStringId)); var isNew = false; myTrade = securityData.MyTrades.SafeAdd(Tuple.Create(order.TransactionId, trade.Id), key => { isNew = true; var t = EntityFactory.CreateMyTrade(order, trade); if (t.ExtensionInfo == null) { t.ExtensionInfo = new Dictionary <object, object>(); } if (message.Commission != null) { t.Commission = message.Commission; } if (message.Slippage != null) { t.Slippage = message.Slippage; } if (message.PnL != null) { t.PnL = message.PnL; } if (message.Position != null) { t.Position = message.Position; } message.CopyExtensionInfo(t); _myTrades.Add(t); return(t); }); return(Tuple.Create(myTrade, isNew)); }
public IEnumerable <Tuple <OrderFail, bool> > ProcessOrderFailMessage(Order order, Security security, ExecutionMessage message) { if (security == null) { throw new ArgumentNullException(nameof(security)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } var data = GetData(security); var orders = new List <Tuple <Order, bool> >(); if (message.OriginalTransactionId == 0) { throw new ArgumentOutOfRangeException(nameof(message), message.OriginalTransactionId, LocalizedStrings.Str715); } var orderType = message.OrderType; if (order == null) { var cancelledOrder = data.Orders.TryGetValue(CreateOrderKey(orderType, message.OriginalTransactionId, true))?.Order; if (cancelledOrder == null && orderType == null) { cancelledOrder = data.Orders.TryGetValue(CreateOrderKey(OrderTypes.Conditional, message.OriginalTransactionId, true))?.Order; if (cancelledOrder != null) { orderType = OrderTypes.Conditional; } } if (cancelledOrder != null /*&& order.Id == message.OrderId*/) { orders.Add(Tuple.Create(cancelledOrder, true)); } var registeredOrder = data.Orders.TryGetValue(CreateOrderKey(orderType, message.OriginalTransactionId, false))?.Order; if (registeredOrder == null && orderType == null) { registeredOrder = data.Orders.TryGetValue(CreateOrderKey(OrderTypes.Conditional, message.OriginalTransactionId, false))?.Order; } if (registeredOrder != null) { orders.Add(Tuple.Create(registeredOrder, false)); } if (cancelledOrder == null && registeredOrder == null) { if (!message.OrderStringId.IsEmpty()) { order = data.OrdersByStringId.TryGetValue(message.OrderStringId); if (order != null) { var pair = data.Orders.LastOrDefault(p => p.Value.Order == order); if (pair.Key != null) { orders.Add(Tuple.Create(pair.Value.Order, pair.Key.Item3)); } } } } } else { if (data.Orders.ContainsKey(CreateOrderKey(order.Type, message.OriginalTransactionId, true))) { orders.Add(Tuple.Create(order, true)); } var registeredOrder = data.Orders.TryGetValue(CreateOrderKey(order.Type, message.OriginalTransactionId, false))?.Order; if (registeredOrder != null) { orders.Add(Tuple.Create(registeredOrder, false)); } } if (orders.Count == 0) { return(Enumerable.Empty <Tuple <OrderFail, bool> >()); } return(orders.Select(t => { var o = t.Item1; var isCancelTransaction = t.Item2; o.LastChangeTime = message.ServerTime; o.LocalTime = message.LocalTime; if (message.OrderStatus != null) { o.Status = message.OrderStatus; } //для ошибок снятия не надо менять состояние заявки if (!isCancelTransaction) { o.State = o.State.CheckModification(OrderStates.Failed); } if (message.Commission != null) { o.Commission = message.Commission; } message.CopyExtensionInfo(o); var error = message.Error ?? new InvalidOperationException(isCancelTransaction ? LocalizedStrings.Str716 : LocalizedStrings.Str717); var fail = EntityFactory.CreateOrderFail(o, error); fail.ServerTime = message.ServerTime; fail.LocalTime = message.LocalTime; return Tuple.Create(fail, isCancelTransaction); })); }
public IEnumerable <OrderChangeInfo> ApplyChanges(ExecutionMessage message, bool isCancel, Action <Order> process) { if (process is null) { throw new ArgumentNullException(nameof(process)); } var order = Order; OrderChangeInfo retVal; if (order.State == OrderStates.Done) { // данные о заявке могут приходить из маркет-дата и транзакционного адаптеров retVal = new OrderChangeInfo(order, _raiseNewOrder, false); _raiseNewOrder = false; process(order); yield return(retVal); //throw new InvalidOperationException("Изменение заявки в состоянии Done невозможно."); } else if (order.State == OrderStates.Failed) { // some adapters can resend order's info //throw new InvalidOperationException(); yield break; } var isPending = order.State == OrderStates.Pending; // is we have Pending order and received Done event // add intermediate Active event if (isPending && message.OrderState == OrderStates.Done) { var clone = message.TypedClone(); clone.OrderState = OrderStates.Active; clone.Balance = null; foreach (var i in ApplyChanges(clone, false, process)) { yield return(i); } } if (message.OrderId != null) { order.Id = message.OrderId.Value; } if (!message.OrderStringId.IsEmpty()) { order.StringId = message.OrderStringId; } if (!message.OrderBoardId.IsEmpty()) { order.BoardId = message.OrderBoardId; } if (message.Balance != null) { order.Balance = ((decimal?)order.Balance).ApplyNewBalance(message.Balance.Value, order.TransactionId, _parent._logReceiver); } if (message.OrderState != null) { order.ApplyNewState(message.OrderState.Value, _parent._logReceiver); } if (order.Time == DateTimeOffset.MinValue) { order.Time = message.ServerTime; } // для новых заявок используем серверное время, // т.к. заявка получена первый раз и не менялась // ServerTime для заявки - это время регистрации order.LastChangeTime = _raiseNewOrder ? message.ServerTime : message.LocalTime; order.LocalTime = message.LocalTime; //нулевой объем может быть при перерегистрации if (order.Volume == 0 && message.OrderVolume != null) { order.Volume = message.OrderVolume.Value; } if (message.Commission != null) { order.Commission = message.Commission; } if (!message.CommissionCurrency.IsEmpty()) { order.CommissionCurrency = message.CommissionCurrency; } if (message.TimeInForce != null) { order.TimeInForce = message.TimeInForce.Value; } if (message.Latency != null) { if (isCancel) { order.LatencyCancellation = message.Latency.Value; } else if (isPending) { if (order.State != OrderStates.Pending) { order.LatencyRegistration = message.Latency.Value; } } } if (message.AveragePrice != null) { order.AveragePrice = message.AveragePrice; } if (message.Yield != null) { order.Yield = message.Yield; } message.CopyExtensionInfo(order); retVal = new OrderChangeInfo(order, _raiseNewOrder, true); _raiseNewOrder = false; process(order); yield return(retVal); }
public OrderChangeInfo ApplyChanges(ExecutionMessage message, bool isCancel) { var order = Order; OrderChangeInfo retVal; if (order.State == OrderStates.Done) { // данные о заявке могут приходить из маркет-дата и транзакционного адаптеров retVal = OrderChangeInfo.Create(order, _raiseNewOrder, false); _raiseNewOrder = false; return(retVal); //throw new InvalidOperationException("Изменение заявки в состоянии Done невозможно."); } else if (order.State == OrderStates.Failed) { // some adapters can resend order's info //throw new InvalidOperationException(); return(null); } var isPending = order.State == OrderStates.Pending; if (message.OrderId != null) { order.Id = message.OrderId.Value; } if (!message.OrderStringId.IsEmpty()) { order.StringId = message.OrderStringId; } if (!message.OrderBoardId.IsEmpty()) { order.BoardId = message.OrderBoardId; } if (message.Balance != null) { if (order.Balance < message.Balance.Value) { _parent._logReceiver.AddErrorLog($"Order {order.TransactionId}: bal_old {order.Balance} -> bal_new {message.Balance.Value}"); } order.Balance = message.Balance.Value; } if (message.OrderState != null) { order.State = order.State.CheckModification(message.OrderState.Value); } if (order.Time == DateTimeOffset.MinValue) { order.Time = message.ServerTime; } // для новых заявок используем серверное время, // т.к. заявка получена первый раз и не менялась // ServerTime для заявки - это время регистрации order.LastChangeTime = _raiseNewOrder ? message.ServerTime : message.LocalTime; order.LocalTime = message.LocalTime; //нулевой объем может быть при перерегистрации if (order.Volume == 0 && message.OrderVolume != null) { order.Volume = message.OrderVolume.Value; } if (message.Commission != null) { order.Commission = message.Commission; } if (!message.CommissionCurrency.IsEmpty()) { order.CommissionCurrency = message.CommissionCurrency; } if (message.TimeInForce != null) { order.TimeInForce = message.TimeInForce.Value; } if (message.Latency != null) { if (isCancel) { order.LatencyCancellation = message.Latency.Value; } else if (isPending) { if (order.State != OrderStates.Pending) { order.LatencyRegistration = message.Latency.Value; } } } if (message.AveragePrice != null) { order.AveragePrice = message.AveragePrice; } if (message.Yield != null) { order.Yield = message.Yield; } message.CopyExtensionInfo(order); retVal = OrderChangeInfo.Create(order, _raiseNewOrder, true); _raiseNewOrder = false; return(retVal); }
private Tuple <MyTrade, bool> AddMyTrade(Order order, Trade trade, ExecutionMessage message) { if (order == null) { throw new ArgumentNullException("order"); } if (trade == null) { throw new ArgumentNullException("trade"); } var isNew = false; var myTrade = _cache.GetData(order.Security).MyTrades.SafeAdd(Tuple.Create(order.TransactionId, trade.Id), key => { isNew = true; var t = EntityFactory.CreateMyTrade(order, trade); if (t.ExtensionInfo == null) { t.ExtensionInfo = new Dictionary <object, object>(); } if (message.Commission != null) { t.Commission = message.Commission; } if (message.Slippage != null) { t.Slippage = message.Slippage; } message.CopyExtensionInfo(t); //trades.Add(t); _cache.MyTrades.Add(t); return(t); }); return(Tuple.Create(myTrade, isNew)); // mika // http://stocksharp.com/forum/yaf_postst1072_Probliemy-so-sdielkami--pozitsiiami.aspx // из-за того, что сделки по заявке иногда приходит быстрее события NewOrders, неправильно расчитывается поза по стратегиям //var raiseOrderChanged = false; //trades.SyncDo(d => //{ // var newBalance = order.Volume - d.Sum(t => t.Trade.Volume); // if (order.Balance > newBalance) // { // raiseOrderChanged = true; // order.Balance = newBalance; // if (order.Balance == 0) // order.State = OrderStates.Done; // } //}); //if (raiseOrderChanged) // RaiseOrderChanged(order); }