Example #1
0
 /// <summary>
 /// Подписаться на получение свечек.
 /// </summary>
 /// <param name="series">Серия свечек.</param>
 /// <param name="from">Начальная дата, с которой необходимо получать данные.</param>
 /// <param name="to">Конечная дата, до которой необходимо получать данные.</param>
 public void SubscribeCandles(CandleSeries series, DateTimeOffset from, DateTimeOffset to)
 {
     SubscribeCandles(series, from, to, TransactionIdGenerator.GetNextId());
 }
 public PointOfSaleServiceBuilder WithGenerator(TransactionIdGenerator generator)
 {
     this.generator = generator;
     return(this);
 }
Example #3
0
        /// <summary>
        /// Process <see cref="MessageAdapterWrapper.InnerAdapter"/> output message.
        /// </summary>
        /// <param name="message">The message.</param>
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            if (message.IsBack)
            {
                base.OnInnerAdapterNewOutMessage(message);
                return;
            }

            List <Message> messages = null;
            List <Message> clones   = null;

            switch (message.Type)
            {
            case MessageTypes.Connect:
            {
                var connectMsg = (ConnectMessage)message;

                if (connectMsg.Error == null && IsRestoreOnReconnect)
                {
                    messages = new List <Message>();

                    lock (_sync)
                    {
                        messages.AddRange(_subscribers.Values.Select(p => p.Message));
                        messages.AddRange(_newsSubscribers.Values.Select(p => p.Message));
                        messages.AddRange(_pfSubscribers.Values.Select(p => p.First));

                        ClearSubscribers();
                    }

                    if (messages.Count == 0)
                    {
                        messages = null;
                    }
                }

                break;
            }

            case ExtendedMessageTypes.RestoringSubscription:
            {
                if (IsRestoreOnReconnect)
                {
                    messages = new List <Message>();

                    lock (_sync)
                    {
                        messages.AddRange(_subscribers.Values.Select(p => p.Message));
                        messages.AddRange(_newsSubscribers.Values.Select(p => p.Message));
                        messages.AddRange(_pfSubscribers.Values.Select(p => p.First));

                        ClearSubscribers();
                    }

                    if (messages.Count == 0)
                    {
                        messages = null;
                    }
                }

                break;
            }

            case MessageTypes.MarketData:
            {
                if (ProcessOutMarketDataMessage((MarketDataMessage)message))
                {
                    return;
                }

                break;
            }

            case MessageTypes.CandleTimeFrame:
            case MessageTypes.CandlePnF:
            case MessageTypes.CandleRange:
            case MessageTypes.CandleRenko:
            case MessageTypes.CandleTick:
            case MessageTypes.CandleVolume:
            {
                clones = ReplicateMessages(message);
                break;
            }

            case MessageTypes.Execution:
            {
                var execMsg = (ExecutionMessage)message;

                switch (execMsg.ExecutionType)
                {
                case ExecutionTypes.Tick:
                case ExecutionTypes.OrderLog:
                {
                    clones = ReplicateMessages(message);
                    break;
                }
                }

                break;
            }

            case MessageTypes.News:
            {
                clones = ReplicateMessages(message);
                break;
            }
            }

            base.OnInnerAdapterNewOutMessage(message);

            if (clones != null)
            {
                foreach (var clone in clones)
                {
                    base.OnInnerAdapterNewOutMessage(clone);
                }
            }

            if (messages != null)
            {
                foreach (var m in messages)
                {
                    var msg = m.Clone();

                    msg.IsBack  = true;
                    msg.Adapter = this;

                    if (msg is MarketDataMessage mdMsg)
                    {
                        mdMsg.TransactionId = TransactionIdGenerator.GetNextId();
                    }
                    else if (msg is PortfolioMessage pfMsg)
                    {
                        pfMsg.TransactionId = TransactionIdGenerator.GetNextId();
                    }

                    base.OnInnerAdapterNewOutMessage(msg);
                }
            }
        }
        /// <summary>
        /// Зарегистрировать транзакцию.
        /// </summary>
        /// <param name="transaction">Транзакция.</param>
        public void RegisterTransaction(Transaction transaction)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException(nameof(transaction));
            }

            if (transaction.GetInstruction <long>(Transaction.TransactionId) != 0)
            {
                throw new ArgumentException();
            }

            var transactionId = transaction.TryGetTransactionId();

            if (transactionId == 0)
            {
                transactionId = TransactionIdGenerator.GetNextId();
            }

            if (transactionId <= 0 || transactionId > uint.MaxValue)
            {
                throw new InvalidOperationException(LocalizedStrings.Str1700Params.Put(transactionId));
            }

            FormatTransaction.SafeInvoke(transaction.SetTransactionId(transactionId));

            _transactions.Add(transactionId, transaction);

            if (IsAsyncMode)
            {
                Api.SendAsyncTransaction(transaction.ToString());
            }
            else
            {
                Exception error = null;

                // http://stocksharp.com/forum/yaf_postst2247_Oshibka-pri-kotirovanii--sinkhronnyie-tranzaktsii.aspx

                var execution = transaction.Message.ToExecutionMessage();

                if (execution == null)
                {
                    throw new ArgumentException(LocalizedStrings.Str1835, nameof(transaction));
                }

                var isReRegistering = transaction.TransactionType == TransactionTypes.ReRegister;
                var isRegistering   = transaction.TransactionType == TransactionTypes.Register || isReRegistering;

                var apiMessage = "";

                try
                {
                    long        orderId;
                    uint        transId;
                    OrderStatus status;

                    var transactionTxt = transaction.ToString();

                    Api.SendSyncTransaction(transactionTxt, out status, out transId, out orderId, out apiMessage);

                    var isMatchOrCancel = (transaction.Message.Type == MessageTypes.OrderRegister || transaction.Message.Type == MessageTypes.OrderReplace) &&
                                          ((OrderRegisterMessage)transaction.Message).TimeInForce == TimeInForce.MatchOrCancel;

                    if ((!isMatchOrCancel && status != OrderStatus.Accepted) || (isMatchOrCancel && !TransactionHelper.IfFOKCancelMessage(apiMessage) && orderId == 0))
                    {
                        throw new InvalidOperationException(LocalizedStrings.Str1836Params.Put(transactionTxt, apiMessage));
                    }

                    execution.OrderStatus   = status;
                    execution.SystemComment = apiMessage;

                    if (isRegistering)
                    {
                        ProcessTransactionReply(execution, transaction, orderId, apiMessage, Codes.Success, null);
                    }
                }
                catch (Exception ex)
                {
                    var apiEx = ex as ApiException;

                    if (isRegistering)
                    {
                        ProcessTransactionReply(execution, transaction, 0, apiMessage, apiEx != null ? apiEx.Code : Codes.Failed, ex);
                    }
                    else
                    {
                        execution.OrderState = OrderStates.Failed;
                        execution.Error      = apiEx ?? new ApiException(Codes.Failed, apiMessage);
                        SendOutMessage(execution);
                    }

                    error = ex;
                }

                if (error != null)
                {
                    error.Throw();
                }
            }
        }
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            long TryReplaceOriginId(long id)
            {
                if (id == 0)
                {
                    return(0);
                }

                lock (_sync)
                    return(_replaceId.TryGetValue(id, out var prevId) ? prevId : id);
            }

            var prevOriginId = 0L;
            var newOriginId  = 0L;

            if (message is IOriginalTransactionIdMessage originIdMsg1)
            {
                newOriginId  = originIdMsg1.OriginalTransactionId;
                prevOriginId = originIdMsg1.OriginalTransactionId = TryReplaceOriginId(newOriginId);
            }

            switch (message.Type)
            {
            case MessageTypes.SubscriptionResponse:
            {
                lock (_sync)
                {
                    if (((SubscriptionResponseMessage)message).IsOk())
                    {
                        if (_subscriptionsById.TryGetValue(prevOriginId, out var info))
                        {
                            // no need send response after re-subscribe cause response was handled prev time
                            if (_replaceId.ContainsKey(newOriginId))
                            {
                                if (info.State != SubscriptionStates.Stopped)
                                {
                                    return;
                                }
                            }
                            else
                            {
                                ChangeState(info, SubscriptionStates.Active);
                            }
                        }
                    }
                    else
                    {
                        if (!_historicalRequests.Remove(prevOriginId))
                        {
                            if (_subscriptionsById.TryGetAndRemove(prevOriginId, out var info))
                            {
                                ChangeState(info, SubscriptionStates.Error);

                                _replaceId.Remove(newOriginId);
                            }
                        }
                    }
                }

                break;
            }

            case MessageTypes.SubscriptionOnline:
            {
                lock (_sync)
                {
                    if (!_subscriptionsById.TryGetValue(prevOriginId, out var info))
                    {
                        break;
                    }

                    if (_replaceId.ContainsKey(newOriginId))
                    {
                        // no need send response after re-subscribe cause response was handled prev time

                        if (info.State == SubscriptionStates.Online)
                        {
                            return;
                        }
                    }
                    else
                    {
                        ChangeState(info, SubscriptionStates.Online);
                    }
                }

                break;
            }

            case MessageTypes.SubscriptionFinished:
            {
                lock (_sync)
                {
                    if (_replaceId.ContainsKey(newOriginId))
                    {
                        return;
                    }

                    _historicalRequests.Remove(prevOriginId);
                }

                break;
            }

            default:
            {
                if (message is ISubscriptionIdMessage subscrMsg)
                {
                    lock (_sync)
                    {
                        var ids = subscrMsg.GetSubscriptionIds();

                        if (ids.Length == 0)
                        {
                            if (subscrMsg.OriginalTransactionId != 0 && _historicalRequests.ContainsKey(subscrMsg.OriginalTransactionId))
                            {
                                subscrMsg.SetSubscriptionIds(subscriptionId: subscrMsg.OriginalTransactionId);
                            }
                        }
                        else
                        {
                            lock (_sync)
                            {
                                if (_replaceId.Count > 0)
                                {
                                    subscrMsg.SetSubscriptionIds(ids.Select(id => _replaceId.TryGetValue2(id) ?? id).ToArray());
                                }
                            }
                        }
                    }
                }

                break;
            }
            }

            base.OnInnerAdapterNewOutMessage(message);

            switch (message.Type)
            {
            case ExtendedMessageTypes.ReconnectingFinished:
            {
                ProcessSuspendedMessage supended = null;

                lock (_sync)
                {
                    _replaceId.Clear();
                    _reMapSubscriptions.Clear();

                    _reMapSubscriptions.AddRange(_subscriptionsById.Values.Distinct().Select(i =>
                        {
                            var subscription           = i.Subscription.TypedClone();
                            subscription.TransactionId = TransactionIdGenerator.GetNextId();

                            _replaceId.Add(subscription.TransactionId, i.Subscription.TransactionId);

                            this.AddInfoLog("Re-map subscription: {0}->{1} for '{2}'.", i.Subscription.TransactionId, subscription.TransactionId, i.Subscription);

                            return((Message)subscription);
                        }));

                    if (_reMapSubscriptions.Count > 0)
                    {
                        supended = new ProcessSuspendedMessage(this);
                    }
                }

                if (supended != null)
                {
                    base.OnInnerAdapterNewOutMessage(supended);
                }

                break;
            }
            }
        }
Example #6
0
        /// <summary>
        /// Send message.
        /// </summary>
        /// <param name="message">Message.</param>
        public override void SendInMessage(Message message)
        {
            if (message.IsBack)
            {
                if (message.Adapter == this)
                {
                    message.Adapter = null;
                    message.IsBack  = false;
                }
                else
                {
                    base.SendInMessage(message);
                    return;
                }
            }

            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_sync)
                {
                    ClearSubscribers();
                    //_pendingMessages.Clear();
                }

                base.SendInMessage(message);
                break;
            }

            case MessageTypes.Disconnect:
            {
                if (!IsRestoreOnReconnect)
                {
                    var messages = new List <Message>();

                    lock (_sync)
                    {
                        if (_newsSubscribers.Count > 0)
                        {
                            messages.AddRange(_newsSubscribers.Values.Select(p => p.First));
                        }

                        if (_subscribers.Count > 0)
                        {
                            messages.AddRange(_subscribers.Values.Select(p => p.First));
                        }

                        if (_candleSubscribers.Count > 0)
                        {
                            messages.AddRange(_candleSubscribers.Values.Select(p => p.First));
                        }

                        if (_pfSubscribers.Count > 0)
                        {
                            messages.AddRange(_pfSubscribers.Values.Select(p => p.First));
                        }

                        ClearSubscribers();
                    }

                    foreach (var m in messages)
                    {
                        var msg = m.Clone();

                        if (msg is MarketDataMessage mdMsg)
                        {
                            mdMsg.TransactionId = TransactionIdGenerator.GetNextId();
                            mdMsg.IsSubscribe   = false;
                        }
                        else
                        {
                            var pfMsg = (PortfolioMessage)msg;

                            pfMsg.TransactionId = TransactionIdGenerator.GetNextId();
                            pfMsg.IsSubscribe   = false;
                        }

                        base.SendInMessage(msg);
                    }
                }

                base.SendInMessage(message);
                break;
            }

            case MessageTypes.MarketData:
                ProcessInMarketDataMessage((MarketDataMessage)message);
                break;

            case MessageTypes.Portfolio:
                ProcessInPortfolioMessage((PortfolioMessage)message);
                break;

            default:
                base.SendInMessage(message);
                break;
            }
        }
Example #7
0
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            long TryReplaceOriginId(long id)
            {
                if (id == 0)
                {
                    return(0);
                }

                lock (_sync)
                    return(_replaceId.TryGetValue(id, out var prevId) ? prevId : id);
            }

            var prevOriginId = 0L;
            var newOriginId  = 0L;

            if (message is IOriginalTransactionIdMessage originIdMsg1)
            {
                newOriginId  = originIdMsg1.OriginalTransactionId;
                prevOriginId = originIdMsg1.OriginalTransactionId = TryReplaceOriginId(newOriginId);
            }

            bool UpdateSubscriptionResult(bool isOk, Func <long, Message> createReply)
            {
                HashSet <long> subscribers = null;

                lock (_sync)
                {
                    if (isOk)
                    {
                        if (_subscriptionsById.TryGetValue(prevOriginId, out var info))
                        {
                            // no need send response after re-subscribe cause response was handled prev time
                            if (_replaceId.ContainsKey(newOriginId))
                            {
                                if (info.State != SubscriptionStates.Stopped)
                                {
                                    return(false);
                                }
                            }
                            else
                            {
                                ChangeState(info, SubscriptionStates.Active);
                            }
                        }
                    }
                    else
                    {
                        if (!_historicalRequests.Remove(prevOriginId))
                        {
                            if (_subscriptionsById.TryGetAndRemove(prevOriginId, out var info))
                            {
                                ChangeState(info, SubscriptionStates.Error);

                                _replaceId.Remove(newOriginId);
                                _subscriptionsByKey.RemoveByValue(info);

                                var set = new HashSet <long>(info.Subscribers.Cache);
                                set.Remove(prevOriginId);
                                subscribers = set;
                            }
                        }
                    }
                }

                if (subscribers != null)
                {
                    foreach (var subscriber in subscribers)
                    {
                        base.OnInnerAdapterNewOutMessage(createReply(subscriber));
                    }
                }

                return(true);
            }

            switch (message.Type)
            {
            case MessageTypes.MarketData:
            {
                var responseMsg = (MarketDataMessage)message;

                if (!UpdateSubscriptionResult(responseMsg.IsOk(), subscriber => new MarketDataMessage
                    {
                        OriginalTransactionId = subscriber,
                        Error = responseMsg.Error,
                        IsNotSupported = responseMsg.IsNotSupported,
                    }))
                {
                    return;
                }

                break;
            }

            case MessageTypes.SubscriptionOnline:
            {
                lock (_sync)
                {
                    if (!_subscriptionsById.TryGetValue(prevOriginId, out var info))
                    {
                        break;
                    }

                    if (_replaceId.ContainsKey(newOriginId))
                    {
                        // no need send response after re-subscribe cause response was handled prev time

                        if (info.State == SubscriptionStates.Online)
                        {
                            return;
                        }
                    }
                    else
                    {
                        ChangeState(info, SubscriptionStates.Online);
                    }
                }

                break;
            }

            case MessageTypes.MarketDataFinished:
            case MessageTypes.SecurityLookupResult:
            case MessageTypes.PortfolioLookupResult:
            case MessageTypes.OrderStatus:
            {
                lock (_sync)
                {
                    if (_replaceId.ContainsKey(newOriginId))
                    {
                        return;
                    }

                    _historicalRequests.Remove(prevOriginId);
                }

                break;
            }

            case MessageTypes.Portfolio:
            {
                var pfMsg = (PortfolioMessage)message;

                // reply on RegisterPortfolio subscription do not contains any portfolio info
                if (pfMsg.PortfolioName.IsEmpty())
                {
                    if (!UpdateSubscriptionResult(pfMsg.Error == null, subscriber => new PortfolioMessage
                        {
                            OriginalTransactionId = subscriber,
                            Error = pfMsg.Error,
                        }))
                    {
                        return;
                    }
                }

                break;
            }

            default:
            {
                if (message is ISubscriptionIdMessage subscrMsg)
                {
                    lock (_sync)
                    {
                        if (subscrMsg.OriginalTransactionId != 0 && _historicalRequests.ContainsKey(subscrMsg.OriginalTransactionId))
                        {
                            subscrMsg.SetSubscriptionIds(subscriptionId: subscrMsg.OriginalTransactionId);
                        }
                        else
                        {
                            if (subscrMsg.OriginalTransactionId != 0 && _subscriptionsById.TryGetValue(subscrMsg.OriginalTransactionId, out var info))
                            {
                            }
                            else
                            {
                                var dataType = message.Type.ToDataType((message as CandleMessage)?.Arg ?? (message as ExecutionMessage)?.ExecutionType);
                                var secId    = GetSecurityId(dataType, (subscrMsg as ISecurityIdMessage)?.SecurityId ?? default);

                                if (!_subscriptionsByKey.TryGetValue(Tuple.Create(dataType, secId), out info))
                                {
                                    break;
                                }
                            }

                            subscrMsg.SetSubscriptionIds(info.Subscribers.Cache);
                        }
                    }
                }

                break;
            }
            }

            base.OnInnerAdapterNewOutMessage(message);

            switch (message.Type)
            {
            case ExtendedMessageTypes.ReconnectingFinished:
            {
                Message[] subscriptions;

                lock (_sync)
                {
                    _replaceId.Clear();

                    subscriptions = _subscriptionsById.Values.Distinct().Select(i =>
                        {
                            var subscription           = (ISubscriptionMessage)i.Subscription.Clone();
                            subscription.TransactionId = TransactionIdGenerator.GetNextId();

                            _replaceId.Add(subscription.TransactionId, i.Subscription.TransactionId);

                            this.AddInfoLog("Re-map subscription: {0}->{1} for '{2}'.", i.Subscription.TransactionId, subscription.TransactionId, i.Subscription);

                            return(((Message)subscription).LoopBack(this));
                        }).ToArray();
                }

                foreach (var subscription in subscriptions)
                {
                    base.OnInnerAdapterNewOutMessage(subscription);
                }

                break;
            }
            }
        }
        private void ProcessOrderStatus()
        {
            if (_requestOrderFirst)
            {
                _requestOrderFirst = false;

                var orders = _httpClient.RequestOpenOrders().ToArray();

                foreach (var o in orders)
                {
                    var order = o;
                    _orderInfo.SafeAdd(order.Id, key => RefTuple.Create(TransactionIdGenerator.GetNextId(), (decimal)order.Amount));
                }

                var trades = _httpClient.RequestUserTransactions().ToArray();

                foreach (var trade in trades.OrderBy(t => t.Id))
                {
                    var info = _orderInfo.TryGetValue(trade.OrderId);

                    if (info == null)
                    {
                        continue;
                    }

                    info.Second -= (decimal)trade.BtcAmount;
                }

                _hasActiveOrders = false;

                foreach (var order in orders)
                {
                    _hasActiveOrders = true;
                    ProcessOrder(order);
                }

                _hasMyTrades = false;

                foreach (var trade in trades)
                {
                    ProcessExecution(trade);
                }

                return;
            }

            if (_hasMyTrades)
            {
                var transactions = _httpClient.RequestUserTransactions();

                _hasMyTrades = false;

                foreach (var trade in transactions.Where(t => t.Type == 2).OrderBy(t => t.Id))
                {
                    ProcessExecution(trade);
                }
            }

            if (_hasActiveOrders)
            {
                var orders = _httpClient.RequestOpenOrders();

                _hasActiveOrders = false;

                foreach (var order in orders)
                {
                    _hasActiveOrders = true;
                    ProcessOrder(order);
                }
            }
        }
        private void OnProcessOrders(string[] data)
        {
            var f = Wrapper.FieldsOrders;

            if (data.Length > 0)
            {
                this.AddLog(LogLevels.Debug, () => "OnProcessOrders:\n" + data.Join("\n"));
            }

            foreach (var str in data)
            {
                var cols = str.ToColumns();

                // 83487901|41469-000|42550|M|B|8356|1|1|0:00:00||FORTS|0|
                // ...
                // 83487901|41469-000|42550|M|B|8356|1|0|12.12.2011 16:31:41|2198931532|FORTS|0|
                // NOTE: когда в первый раз приходит апдейт по заявке в нем нет ни времени, ни комментария.

                // 84352688|41469-000|12910|M|S|80.13|10|0|22.12.2011 17:16:58||MICEX_SHR|0|0|
                // 84352688|41469-000|12910|M|S|80.13|10|0|22.12.2011 17:16:58|2968835969|MICEX_SHR|0|80.408|
                // NOTE: на ММВБ заявка сперва приходит с пустым комментарием!

                var orderId = f.OrdNo.GetValue(cols);
                var transId = f.Comments.GetValue(cols);

                if (transId == 0)
                {
                    var alfaTransactionId = _alfaIds.TryGetKey(orderId);
                    transId = _localIds.TryGetKey(alfaTransactionId);

                    if (transId == 0)
                    {
                        this.AddWarningLog("transaction id for order #{0} not found. creating new one.", orderId);
                        transId = TransactionIdGenerator.GetNextId();
                        if (alfaTransactionId == 0)
                        {
                            alfaTransactionId = --_lastFakeAlfaTransactionId;
                            _alfaIds.Add(alfaTransactionId, orderId);
                        }
                        _localIds.Add(transId, alfaTransactionId);
                    }
                }

                var msg = new ExecutionMessage
                {
                    SecurityId = new SecurityId {
                        Native = f.PaperNo.GetValue(cols)
                    },
                    PortfolioName         = GetPortfolioName(f.AccCode.GetValue(cols), this.GetBoardCode(f.PlaceCode.GetValue(cols))),
                    Side                  = f.BuySellStr.GetValue(cols),
                    Price                 = f.Price.GetValue(cols),
                    Volume                = f.Qty.GetValue(cols),
                    Balance               = f.Rest.GetValue(cols),
                    OriginalTransactionId = transId,
                    OrderId               = orderId,
                    ExecutionType         = ExecutionTypes.Order,
                };

                var orderTime = f.TsTime.GetValue(cols);
                if (orderTime.TimeOfDay != TimeSpan.Zero)
                {
                    msg.ServerTime = orderTime.ApplyTimeZone(TimeHelper.Moscow);
                }

                var stopPrice = f.StopPrice.GetValue(cols);
                var orderType = f.Blank.GetValue(cols);

                switch (orderType)
                {
                case "S":
                {
                    var updateToPrice = f.UpdateNewPrice.GetValue(cols);

                    if (updateToPrice != 0)                             // Stop + TargetProfit
                    {
                        var updGrowPrice = f.UpdateGrowPrice.GetValue(cols);
                        var updDownPrice = f.UpdateDownPrice.GetValue(cols);

                        msg.Condition = new AlfaOrderCondition
                        {
                            StopPrice   = stopPrice,
                            TargetPrice = msg.Price,
                            Slippage    = msg.Side == Sides.Buy
                                                                                           ? updateToPrice - updGrowPrice
                                                                                           : updDownPrice - updateToPrice
                        };
                    }
                    else                             // Stop
                    {
                        msg.Condition = new AlfaOrderCondition
                        {
                            StopPrice = stopPrice,
                            Slippage  = stopPrice == 0
                                                                                           ? 0
                                                                                           : msg.Side == Sides.Buy
                                                                                                         ? msg.Price - stopPrice
                                                                                                         : stopPrice - msg.Price
                        };
                    }

                    msg.OrderType = OrderTypes.Conditional;

                    break;
                }

                case "T":
                {
                    var level    = f.TrailingLevel.GetValue(cols);
                    var slippage = f.TrailingSlippage.GetValue(cols);

                    msg.Condition = new AlfaOrderCondition
                    {
                        Level     = level,
                        Slippage  = slippage,
                        StopPrice = stopPrice
                    };

                    msg.OrderType = OrderTypes.Conditional;

                    break;
                }

                case "L":
                    msg.OrderType = OrderTypes.Limit;
                    break;

                default:
                    this.AddWarningLog("Unknown order type '{0}' (id={1})", orderType, orderId);
                    break;
                }

                var status = f.OrderStatus.GetValue(cols);
                switch (status)
                {
                case "O":                         // активная
                case "G":                         // с условием
                    msg.OrderState = OrderStates.Active;
                    break;

                case "M":                         // исполнена
                    msg.OrderState = msg.Balance != 0 ? OrderStates.Active : OrderStates.Done;
                    break;

                case "W":                         // удалена
                    msg.OrderState = OrderStates.Done;
                    break;

                case "N":                         // принята сервером АД, но пока не на бирже
                    msg.OrderState = OrderStates.Pending;
                    break;

                default:
                    this.AddInfoLog("Order status {0} is not taken into account", status);
                    break;
                }

                SendOutMessage(msg);
            }
        }
        /// <inheritdoc />
        protected override void OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            case MessageTypes.Disconnect:
            {
                lock (_syncObject)
                {
                    _partialRequests.Clear();
                    _original.Clear();
                    _unsubscribeRequests.Clear();
                    _liveRequests.Clear();
                }

                break;
            }

            case MessageTypes.OrderStatus:
            case MessageTypes.PortfolioLookup:
            {
                var subscriptionMsg = (ISubscriptionMessage)message;

                if (subscriptionMsg.IsSubscribe)
                {
                    var from = subscriptionMsg.From;
                    var to   = subscriptionMsg.To;

                    if (from != null || to != null)
                    {
                        var step = InnerAdapter.GetHistoryStepSize(DataType.Transactions, out _);

                        // adapter do not provide historical request
                        if (step == TimeSpan.Zero)
                        {
                            if (to != null)
                            {
                                // finishing current history request

                                if (message.Type == MessageTypes.PortfolioLookup)
                                {
                                    RaiseNewOutMessage(message.Type.ToResultType().CreateLookupResult(subscriptionMsg.TransactionId));
                                }

                                return;
                            }
                            else
                            {
                                // or sending further only live subscription
                                subscriptionMsg.From = null;
                                subscriptionMsg.To   = null;

                                _liveRequests.Add(subscriptionMsg.TransactionId, false);
                            }
                        }
                    }
                    else
                    {
                        _liveRequests.Add(subscriptionMsg.TransactionId, false);
                    }
                }

                break;
            }

            case MessageTypes.MarketData:
            {
                var mdMsg = (MarketDataMessage)message;

                if (mdMsg.IsSubscribe)
                {
                    var from = mdMsg.From;
                    var to   = mdMsg.To;

                    if (from != null || to != null)
                    {
                        var step = InnerAdapter.GetHistoryStepSize(mdMsg.ToDataType(), out var iterationInterval);

                        // adapter do not provide historical request
                        if (step == TimeSpan.Zero)
                        {
                            if (to != null)
                            {
                                // finishing current history request
                                RaiseNewOutMessage(new MarketDataFinishedMessage {
                                        OriginalTransactionId = mdMsg.TransactionId
                                    });
                                return;
                            }
                            else
                            {
                                // or sending further only live subscription
                                mdMsg.From = null;
                                mdMsg.To   = null;

                                _liveRequests.Add(mdMsg.TransactionId, false);
                                break;
                            }
                        }

                        var info = new DownloadInfo(this, (MarketDataMessage)mdMsg.Clone(), step, iterationInterval);

                        message = info.InitNext();

                        lock (_syncObject)
                        {
                            _original.Add(info.Origin.TransactionId, info);
                            _partialRequests.Add(info.CurrTransId, info);
                        }
                    }
                    else
                    {
                        _liveRequests.Add(mdMsg.TransactionId, false);
                    }
                }
                else
                {
                    lock (_syncObject)
                    {
                        if (!_original.TryGetValue(mdMsg.OriginalTransactionId, out var info))
                        {
                            break;
                        }

                        var transId = TransactionIdGenerator.GetNextId();
                        _unsubscribeRequests.Add(transId, Tuple.Create(mdMsg.TransactionId, info));

                        mdMsg.OriginalTransactionId = info.CurrTransId;
                        mdMsg.TransactionId         = transId;
                    }
                }

                break;
            }

            case ExtendedMessageTypes.PartialDownload:
            {
                var partialMsg = (PartialDownloadMessage)message;

                lock (_syncObject)
                {
                    if (!_original.TryGetValue(partialMsg.OriginalTransactionId, out var info))
                    {
                        break;
                    }

                    var mdMsg = info.InitNext();

                    if (mdMsg.To == null)
                    {
                        _liveRequests.Add(mdMsg.TransactionId, true);

                        _original.Remove(partialMsg.OriginalTransactionId);
                        _partialRequests.RemoveWhere(p => p.Value == info);
                    }
                    else
                    {
                        _partialRequests.Add(info.CurrTransId, info);
                    }

                    message = mdMsg;
                }

                break;
            }
            }

            base.OnSendInMessage(message);
        }
        /// <inheritdoc />
        protected override bool OnSendInMessage(Message message)
        {
            void AddInfo(OrderRegisterMessage regMsg)
            {
                if (regMsg is null)
                {
                    throw new ArgumentNullException(nameof(regMsg));
                }

                if (regMsg.OrderType == OrderTypes.Market || regMsg.Price == 0)
                {
                    return;
                }

                if (regMsg.TimeInForce == TimeInForce.MatchOrCancel || regMsg.TimeInForce == TimeInForce.CancelBalance)
                {
                    return;
                }

                lock (_sync)
                {
                    foreach (var info in _byId.Values)
                    {
                        if (info.BookSubscription.SecurityId == regMsg.SecurityId)
                        {
                            info.AddOrder(regMsg);
                        }
                    }
                }
            }

            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_sync)
                {
                    _byId.Clear();
                    _byBookId.Clear();
                    _byOrderStatusId.Clear();
                    _online.Clear();
                    _unsubscribeRequests.Clear();
                }

                break;
            }

            case MessageTypes.OrderRegister:
            case MessageTypes.OrderReplace:
            {
                AddInfo((OrderRegisterMessage)message);
                break;
            }

            case MessageTypes.OrderPairReplace:
            {
                var pairMsg = (OrderPairReplaceMessage)message;

                AddInfo(pairMsg.Message1);
                AddInfo(pairMsg.Message2);

                break;
            }

            case MessageTypes.MarketData:
            {
                var mdMsg = (MarketDataMessage)message;

                if (mdMsg.IsSubscribe)
                {
                    if (mdMsg.SecurityId == default)
                    {
                        break;
                    }

                    if (mdMsg.DataType2 != DataType.FilteredMarketDepth)
                    {
                        break;
                    }

                    var transId = mdMsg.TransactionId;

                    mdMsg = mdMsg.TypedClone();
                    mdMsg.TransactionId = TransactionIdGenerator.GetNextId();
                    mdMsg.DataType2     = DataType.MarketDepth;

                    var orderStatus = new OrderStatusMessage
                    {
                        TransactionId = TransactionIdGenerator.GetNextId(),
                        IsSubscribe   = true,
                        States        = new[] { OrderStates.Active },
                        SecurityId    = mdMsg.SecurityId,
                    };

                    var info = new FilteredMarketDepthInfo(transId, new Subscription(mdMsg, mdMsg), new Subscription(orderStatus, orderStatus));

                    lock (_sync)
                    {
                        _byId.Add(transId, info);
                        _byBookId.Add(mdMsg.TransactionId, info);
                        _byOrderStatusId.Add(orderStatus.TransactionId, info);
                    }

                    this.AddInfoLog("Filtered book {0} started (Book={1} / Orders={2}).", transId, mdMsg.TransactionId, orderStatus.TransactionId);

                    base.OnSendInMessage(mdMsg);
                    base.OnSendInMessage(orderStatus);

                    return(true);
                }
                else
                {
                    MarketDataMessage  bookUnsubscribe   = null;
                    OrderStatusMessage ordersUnsubscribe = null;

                    lock (_sync)
                    {
                        if (!_byId.TryGetValue(mdMsg.OriginalTransactionId, out var info))
                        {
                            break;
                        }

                        info.UnSubscribeId = mdMsg.TransactionId;

                        if (info.BookSubscription.State.IsActive())
                        {
                            bookUnsubscribe = new MarketDataMessage
                            {
                                TransactionId         = TransactionIdGenerator.GetNextId(),
                                OriginalTransactionId = info.BookSubscription.TransactionId,
                                IsSubscribe           = false,
                            };

                            _unsubscribeRequests.Add(bookUnsubscribe.TransactionId, Tuple.Create(info, true));
                        }

                        if (info.OrdersSubscription.State.IsActive())
                        {
                            ordersUnsubscribe = new OrderStatusMessage
                            {
                                TransactionId         = TransactionIdGenerator.GetNextId(),
                                OriginalTransactionId = info.OrdersSubscription.TransactionId,
                                IsSubscribe           = false,
                            };

                            _unsubscribeRequests.Add(ordersUnsubscribe.TransactionId, Tuple.Create(info, false));
                        }
                    }

                    if (bookUnsubscribe == null && ordersUnsubscribe == null)
                    {
                        RaiseNewOutMessage(new SubscriptionResponseMessage
                            {
                                OriginalTransactionId = mdMsg.TransactionId,
                                Error = new InvalidOperationException(LocalizedStrings.SubscriptionNonExist.Put(mdMsg.OriginalTransactionId)),
                            });
                    }
                    else
                    {
                        this.AddInfoLog("Filtered book {0} unsubscribing.", mdMsg.OriginalTransactionId);

                        if (bookUnsubscribe != null)
                        {
                            base.OnSendInMessage(bookUnsubscribe);
                        }

                        if (ordersUnsubscribe != null)
                        {
                            base.OnSendInMessage(ordersUnsubscribe);
                        }
                    }

                    return(true);
                }
            }
            }

            return(base.OnSendInMessage(message));
        }
Example #12
0
		private void ProcessConnectMessage(BaseConnectionMessage message)
		{
			var isConnect = message is ConnectMessage;
			var adapter = message.Adapter;

			if (adapter == null)
			{
				if (message.Error != null)
					RaiseConnectionError(message.Error);

				return;
			}

			var state = _adapterStates[adapter];

			switch (state)
			{
				case ConnectionStates.Connecting:
				{
					if (isConnect)
					{
						if (message.Error == null)
						{
							_adapterStates[adapter] = ConnectionStates.Connected;

							if (ConnectionState == ConnectionStates.Connecting)
							{
								if (RaiseConnectedOnFirstAdapter)
								{
									// raise Connected event only one time for the first adapter
									RaiseConnected();
								}
								else
								{
									var isAllConnected = _adapterStates.CachedValues.All(v => v == ConnectionStates.Connected);

									// raise Connected event only one time when the last adapter connection successfully
									if (isAllConnected)
										RaiseConnected();
								}
							}

							RaiseConnectedEx(adapter);

							if (adapter.PortfolioLookupRequired)
								SendInMessage(new PortfolioLookupMessage { TransactionId = TransactionIdGenerator.GetNextId() });

							if (adapter.OrderStatusRequired)
							{
								var transactionId = TransactionIdGenerator.GetNextId();
								_entityCache.AddOrderStatusTransactionId(transactionId);
								SendInMessage(new OrderStatusMessage { TransactionId = transactionId });
							}

							if (adapter.SecurityLookupRequired)
								SendInMessage(new SecurityLookupMessage { TransactionId = TransactionIdGenerator.GetNextId() });

							if (message is RestoredConnectMessage)
								RaiseRestored();
						}
						else
						{
							_adapterStates[adapter] = ConnectionStates.Failed;

							// raise ConnectionError only one time
							if (ConnectionState == ConnectionStates.Connecting)
							{
								RaiseConnectionError(message.Error);

								if (message.Error is TimeoutException)
									RaiseTimeOut();
							}
							else
								RaiseError(message.Error);

							RaiseConnectionErrorEx(adapter, message.Error);
						}
					}
					else
					{
						_adapterStates[adapter] = ConnectionStates.Failed;

						// raise ConnectionError only one time
						if (ConnectionState == ConnectionStates.Connecting)
							RaiseConnectionError(new InvalidOperationException(LocalizedStrings.Str683, message.Error));
						else
							RaiseError(message.Error);

						RaiseConnectionErrorEx(adapter, message.Error);
					}

					return;
				}
				case ConnectionStates.Disconnecting:
				{
					if (isConnect)
					{
						_adapterStates[adapter] = ConnectionStates.Failed;

						var error = new InvalidOperationException(LocalizedStrings.Str684, message.Error);

						// raise ConnectionError only one time
						if (ConnectionState == ConnectionStates.Disconnecting)
							RaiseConnectionError(error);
						else
							RaiseError(error);

						RaiseConnectionErrorEx(adapter, message.Error);
					}
					else
					{
						if (message.Error == null)
						{
							_adapterStates[adapter] = ConnectionStates.Disconnected;

							var isLast = _adapterStates.CachedValues.All(v => v != ConnectionStates.Disconnecting);

							// raise Disconnected only one time for the last adapter
							if (isLast)
								RaiseDisconnected();

							RaiseDisconnectedEx(adapter);
						}
						else
						{
							_adapterStates[adapter] = ConnectionStates.Failed;

							// raise ConnectionError only one time
							if (ConnectionState == ConnectionStates.Disconnecting)
								RaiseConnectionError(message.Error);
							else
								RaiseError(message.Error);

							RaiseConnectionErrorEx(adapter, message.Error);
						}
					}

					return;
				}
				case ConnectionStates.Connected:
				{
					if (isConnect && message.Error != null)
					{
						_adapterStates[adapter] = ConnectionStates.Failed;
						var error = new InvalidOperationException(LocalizedStrings.Str683, message.Error);
						RaiseConnectionError(error);
						RaiseConnectionErrorEx(adapter, error);
						return;
					}

					break;
				}
				case ConnectionStates.Disconnected:
				case ConnectionStates.Failed:
				{
					//StopMarketTimer();
					break;
				}
				default:
					throw new ArgumentOutOfRangeException();
			}

			// так как соединение установлено, то выдаем ошибку через Error, чтобы не сбрасывать состояние
			var error2 = new InvalidOperationException(LocalizedStrings.Str685Params.Put(state, message.GetType().Name), message.Error);
			RaiseError(error2);
			RaiseConnectionErrorEx(adapter, error2);
		}
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            long TryReplaceOriginId(long id)
            {
                lock (_sync)
                    return(_replaceId.TryGetValue(id, out var prevId) ? prevId : id);
            }

            var newOriginId = 0L;

            if (message is IOriginalTransactionIdMessage originIdMsg1)
            {
                newOriginId = originIdMsg1.OriginalTransactionId;
                originIdMsg1.OriginalTransactionId = TryReplaceOriginId(newOriginId);
            }

            switch (message.Type)
            {
            case MessageTypes.MarketData:
            {
                var responseMsg = (MarketDataMessage)message;

                var originId = responseMsg.OriginalTransactionId;

                lock (_sync)
                {
                    if (responseMsg.IsOk())
                    {
                        // no need send response after re-subscribe cause response was handled prev time
                        if (_replaceId.ContainsKey(newOriginId))
                        {
                            return;
                        }
                    }
                    else
                    {
                        if (!_historicalRequests.Remove(originId))
                        {
                            if (_subscriptionsById.TryGetValue(originId, out var info))
                            {
                                _replaceId.Remove(newOriginId);
                                _subscriptionsById.Remove(originId);
                                _subscriptionsByKey.RemoveByValue(info);
                            }
                        }
                    }
                }

                break;
            }

            case MessageTypes.MarketDataFinished:
            case MessageTypes.SecurityLookupResult:
            case MessageTypes.PortfolioLookupResult:
            case MessageTypes.OrderStatus:
            {
                var resultMsg = (IOriginalTransactionIdMessage)message;

                lock (_sync)
                {
                    _replaceId.Remove(newOriginId);
                    _historicalRequests.Remove(resultMsg.OriginalTransactionId);
                }

                break;
            }

            default:
            {
                if (message is ISubscriptionIdMessage subscrMsg)
                {
                    lock (_sync)
                    {
                        if (subscrMsg.OriginalTransactionId != 0 && _historicalRequests.Contains(subscrMsg.OriginalTransactionId))
                        {
                            subscrMsg.SubscriptionId = subscrMsg.OriginalTransactionId;
                        }
                        else
                        {
                            if (subscrMsg.OriginalTransactionId != 0 && _subscriptionsById.TryGetValue(subscrMsg.OriginalTransactionId, out var info))
                            {
                            }
                            else
                            {
                                var dataType = message.Type.ToDataType((message as CandleMessage)?.Arg ?? (message as ExecutionMessage)?.ExecutionType);
                                var secId    = GetSecurityId(dataType, (subscrMsg as ISecurityIdMessage)?.SecurityId ?? default);

                                if (!_subscriptionsByKey.TryGetValue(Tuple.Create(dataType, secId), out info))
                                {
                                    break;
                                }
                            }

                            subscrMsg.SubscriptionIds = info.Subscribers.Cache;
                        }
                    }
                }

                break;
            }
            }

            base.OnInnerAdapterNewOutMessage(message);

            switch (message.Type)
            {
            case ExtendedMessageTypes.ReconnectingFinished:
            {
                Message[] subscriptions;

                lock (_sync)
                {
                    _replaceId.Clear();

                    subscriptions = _subscriptionsById.Values.Distinct().Select(i =>
                        {
                            var subscription           = (ISubscriptionMessage)i.Subscription.Clone();
                            subscription.TransactionId = TransactionIdGenerator.GetNextId();

                            _replaceId.Add(subscription.TransactionId, i.Subscription.TransactionId);

                            var msg     = (Message)subscription;
                            msg.Adapter = this;
                            msg.IsBack  = true;
                            return(msg);
                        }).ToArray();
                }

                foreach (var subscription in subscriptions)
                {
                    base.OnInnerAdapterNewOutMessage(subscription);
                }

                break;
            }
            }
        }
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            List <Message> extra = null;

            switch (message.Type)
            {
            case MessageTypes.Disconnect:
            case ExtendedMessageTypes.ReconnectingFinished:
            {
                ClearState();
                break;
            }

            case MessageTypes.SubscriptionResponse:
            {
                var responseMsg = (SubscriptionResponseMessage)message;

                if (responseMsg.Error != null)
                {
                    lock (_sync)
                    {
                        if (_parents.TryGetAndRemove(responseMsg.OriginalTransactionId, out var parent))
                        {
                            extra = new List <Message>();

                            foreach (var child in parent.Child.Values)
                            {
                                var childId = child.Origin.TransactionId;

                                if (_allChilds.TryGetValue(childId, out var tuple) && tuple.Second == SubscriptionStates.Stopped)
                                {
                                    // loopback subscription not yet come, so will reply later
                                    tuple.Second = SubscriptionStates.Error;
                                }
                                else
                                {
                                    extra.Add(new SubscriptionResponseMessage {
                                            OriginalTransactionId = childId, Error = responseMsg.Error
                                        });
                                }
                            }
                        }
                    }
                }

                break;
            }

            case MessageTypes.SubscriptionFinished:
            {
                var finishMsg = (SubscriptionFinishedMessage)message;

                lock (_sync)
                {
                    if (_parents.TryGetAndRemove(finishMsg.OriginalTransactionId, out var parent))
                    {
                        extra = new List <Message>();

                        foreach (var child in parent.Child.Values)
                        {
                            var childId = child.Origin.TransactionId;

                            if (_allChilds.TryGetValue(childId, out var tuple) && tuple.Second == SubscriptionStates.Stopped)
                            {
                                // loopback subscription not yet come, so will reply later
                                tuple.Second = SubscriptionStates.Finished;
                            }
                            else
                            {
                                extra.Add(new SubscriptionFinishedMessage {
                                        OriginalTransactionId = childId
                                    });
                            }
                        }
                    }
                }

                break;
            }

            default:
            {
                if (message is ISubscriptionIdMessage subscrMsg && message is ISecurityIdMessage secIdMsg)
                {
                    SubscriptionSecurityAllMessage allMsg = null;

                    bool CheckSubscription(long parentId)
                    {
                        lock (_sync)
                        {
                            if (_parents.TryGetValue(parentId, out var parent))
                            {
                                // parent subscription has security id (not null)
                                if (parent.Origin.SecurityId == secIdMsg.SecurityId)
                                {
                                    return(true);
                                }

                                if (!parent.Child.TryGetValue(secIdMsg.SecurityId, out var child))
                                {
                                    allMsg = new SubscriptionSecurityAllMessage();

                                    parent.Origin.CopyTo(allMsg);

                                    allMsg.ParentTransactionId = parentId;
                                    allMsg.TransactionId       = TransactionIdGenerator.GetNextId();
                                    allMsg.SecurityId          = secIdMsg.SecurityId;

                                    child = new ChildSubscription(allMsg.TypedClone());
                                    child.Subscribers.Add(allMsg.TransactionId, child.Origin);

                                    parent.Child.Add(secIdMsg.SecurityId, child);

                                    allMsg.LoopBack(this, MessageBackModes.Chain);
                                    _allChilds.Add(allMsg.TransactionId, RefTuple.Create(parentId, SubscriptionStates.Stopped));

                                    this.AddDebugLog("New ALL map: {0}/{1} TrId={2}-{3}", child.Origin.SecurityId, child.Origin.DataType2, allMsg.ParentTransactionId, allMsg.TransactionId);
                                }

                                //var subscriptionIds = subscrMsg.GetSubscriptionIds().Where(i => i != parentId).Concat(child.Subscribers.Cache);
                                subscrMsg.SetSubscriptionIds(child.Subscribers.CachedKeys);

                                if (!child.State.IsActive())
                                {
                                    child.Suspended.Add(message);
                                    message = null;

                                    this.AddDebugLog("ALL suspended: {0}/{1}, cnt={2}", child.Origin.SecurityId, child.Origin.DataType2, child.Suspended.Count);
                                }

                                return(true);
                            }
                        }

                        return(false);
                    }

                    foreach (var id in subscrMsg.GetSubscriptionIds())
                    {
                        if (CheckSubscription(id))
                        {
                            break;
                        }
                    }

                    if (allMsg != null)
                    {
                        base.OnInnerAdapterNewOutMessage(allMsg);
                    }
                }

                break;
            }
            }

            if (message != null)
            {
                base.OnInnerAdapterNewOutMessage(message);
            }

            if (extra != null)
            {
                foreach (var m in extra)
                {
                    base.OnInnerAdapterNewOutMessage(m);
                }
            }
        }
Example #15
0
 public PointOfSaleService(ScanBarcodeQuery query, TransactionIdGenerator generator)
 {
     this.query        = query;
     this.generator    = generator;
     this.scannedItems = new List <Item>();
 }
Example #16
0
        /// <inheritdoc />
        protected override void OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                _subscriptions.Clear();
                _subscriptionsById.Clear();
                break;
            }

            case MessageTypes.MarketData:
            {
                var mdMsg = (MarketDataMessage)message;

                if (mdMsg.SecurityId.IsDefault())
                {
                    break;
                }

                var security = _securityProvider.LookupById(mdMsg.SecurityId);

                if (security == null)
                {
                    if (!mdMsg.IsBasket())
                    {
                        break;
                    }

                    security = mdMsg.ToSecurity(_exchangeInfoProvider).ToBasket(_processorProvider);
                }
                else if (!security.IsBasket())
                {
                    break;
                }

                if (mdMsg.IsSubscribe)
                {
                    var processor = _processorProvider.CreateProcessor(security);
                    var info      = new SubscriptionInfo(processor, mdMsg.TransactionId);

                    var dict = _subscriptions.SafeAdd(mdMsg.DataType);
                    _subscriptionsById.Add(mdMsg.TransactionId, info);

                    var inners = new MarketDataMessage[processor.BasketLegs.Length];

                    for (var i = 0; i < inners.Length; i++)
                    {
                        var inner = (MarketDataMessage)mdMsg.Clone();

                        inner.TransactionId = TransactionIdGenerator.GetNextId();
                        inner.SecurityId    = processor.BasketLegs[i];

                        inners[i] = inner;

                        info.LegsSubscriptions.Add(inner.TransactionId);
                        dict.Add(inner.TransactionId, info);
                    }

                    foreach (var inner in inners)
                    {
                        base.OnSendInMessage(inner);
                    }
                }
                else
                {
                    if (!_subscriptionsById.TryGetValue(mdMsg.OriginalTransactionId, out var info))
                    {
                        break;
                    }

                    _subscriptionsById.Remove(mdMsg.OriginalTransactionId);

                    foreach (var id in info.LegsSubscriptions)
                    {
                        base.OnSendInMessage(new MarketDataMessage
                            {
                                TransactionId         = TransactionIdGenerator.GetNextId(),
                                IsSubscribe           = false,
                                OriginalTransactionId = id
                            });
                    }
                }

                RaiseNewOutMessage(new MarketDataMessage
                    {
                        OriginalTransactionId = mdMsg.TransactionId
                    });

                return;
            }
            }

            base.OnSendInMessage(message);
        }
Example #17
0
        /// <summary>
        /// Process <see cref="MessageAdapterWrapper.InnerAdapter"/> output message.
        /// </summary>
        /// <param name="message">The message.</param>
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            List <Message> messages = null;

            switch (message.Type)
            {
            case MessageTypes.Connect:
            {
                var connectMsg = (ConnectMessage)message;

                if (connectMsg.Error == null && IsRestoreOnReconnect)
                {
                    messages = new List <Message>();

                    lock (_sync)
                    {
                        messages.AddRange(_subscribers.Values.Select(p => p.First));
                        messages.AddRange(_newsSubscribers.Values.Select(p => p.First));
                        messages.AddRange(_candleSubscribers.Values.Select(p => p.First));
                        messages.AddRange(_pfSubscribers.Values.Select(p => p.First));

                        ClearSubscribers();
                    }

                    if (messages.Count == 0)
                    {
                        messages = null;
                    }
                }

                break;
            }
                // TODO
                //case MessageTypes.MarketData:
                //	ProcessOutMarketDataMessage((MarketDataMessage)message);
                //	break;
            }

            base.OnInnerAdapterNewOutMessage(message);

            if (messages != null)
            {
                foreach (var m in messages)
                {
                    var msg = m.Clone();

                    msg.IsBack  = true;
                    msg.Adapter = this;

                    if (msg is MarketDataMessage mdMsg)
                    {
                        mdMsg.TransactionId = TransactionIdGenerator.GetNextId();
                    }
                    else
                    {
                        var pfMsg = (PortfolioMessage)msg;
                        pfMsg.TransactionId = TransactionIdGenerator.GetNextId();
                    }

                    base.OnInnerAdapterNewOutMessage(msg);
                }
            }
        }
        private void ProcessOrderStatus(OrderStatusMessage message)
        {
            if (message == null)
            {
                var portfolioRefresh = false;

                var orders = _httpClient.RequestOpenOrders();

                var ids = _orderInfo.Keys.ToSet();

                foreach (var order in orders)
                {
                    ids.Remove(order.Id);

                    var info = _orderInfo.TryGetValue(order.Id);

                    if (info == null)
                    {
                        info = RefTuple.Create(TransactionIdGenerator.GetNextId(), (decimal)order.Amount);

                        _orderInfo.Add(order.Id, info);

                        ProcessOrder(order, (decimal)order.Amount, info.First, 0);

                        portfolioRefresh = true;
                    }
                    else
                    {
                        // balance existing orders tracked by trades
                    }
                }

                var trades = GetTrades();

                foreach (var trade in trades)
                {
                    ProcessTrade(trade);
                }

                foreach (var id in ids)
                {
                    // can be removed from ProcessTrade
                    if (!_orderInfo.TryGetAndRemove(id, out var info))
                    {
                        return;
                    }

                    SendOutMessage(new ExecutionMessage
                    {
                        ExecutionType         = ExecutionTypes.Transaction,
                        HasOrderInfo          = true,
                        OrderId               = id,
                        OriginalTransactionId = info.First,
                        ServerTime            = CurrentTime.ConvertToUtc(),
                        OrderState            = OrderStates.Done,
                    });

                    portfolioRefresh = true;
                }

                if (portfolioRefresh)
                {
                    ProcessPortfolioLookup(null);
                }
            }
            else
            {
                if (!message.IsSubscribe)
                {
                    return;
                }

                var orders = _httpClient.RequestOpenOrders().ToArray();

                foreach (var order in orders)
                {
                    var info = RefTuple.Create(TransactionIdGenerator.GetNextId(), (decimal)order.Amount);

                    _orderInfo.Add(order.Id, info);

                    ProcessOrder(order, (decimal)order.Amount, info.First, message.TransactionId);
                }

                var trades = GetTrades();

                foreach (var trade in trades)
                {
                    ProcessTrade(trade);
                }

                SendSubscriptionResult(message);
            }
        }
        private void ProcessOrderStatus()
        {
            if (_requestOrderFirst)
            {
                _requestOrderFirst = false;

                var orders = _client.GetOrders().Items.Values;

                foreach (var o in orders)
                {
                    var order = o;
                    _orderInfo.SafeAdd(order.Id, key => RefTuple.Create(TransactionIdGenerator.GetNextId(), (decimal)order.Volume));
                }

                var trades = _client.GetMyTrades(0).Items.Values;

                foreach (var trade in trades.OrderBy(t => t.Id))
                {
                    var info = _orderInfo.TryGetValue(trade.OrderId);

                    if (info == null)
                    {
                        continue;
                    }

                    info.Second -= (decimal)trade.Volume;
                }

                _hasActiveOrders = false;

                foreach (var order in orders)
                {
                    _hasActiveOrders = true;
                    ProcessOrder(order);
                }

                _hasMyTrades = false;

                foreach (var trade in trades)
                {
                    ProcessExecution(trade);
                }

                return;
            }

            if (_hasMyTrades)
            {
                var mtReply = _client.GetMyTrades(_lastMyTradeId + 1);

                _hasMyTrades = false;

                foreach (var trade in mtReply.Items.Values.OrderBy(t => t.Id))
                {
                    ProcessExecution(trade);
                }
            }

            if (_hasActiveOrders)
            {
                var orderReply = _client.GetOrders();

                _hasActiveOrders = false;

                foreach (var order in orderReply.Items.Values)
                {
                    _hasActiveOrders = true;
                    ProcessOrder(order);
                }
            }
        }
        private void ProcessOrderStatusMessage()
        {
            foreach (var accountId in _accountIds.CachedValues)
            {
                int?maxOrderId = null;

                while (true)
                {
                    var orders = _restClient.GetOrders(accountId, maxOrderId);

                    var count = 0;

                    foreach (var order in orders)
                    {
                        count++;

                        maxOrderId = order.Id - 1;

                        OandaOrderCondition condition = null;
                        OrderTypes          orderType;

                        if (order.Type != "market" && order.Type != "limit")
                        {
                            orderType = OrderTypes.Conditional;

                            condition = new OandaOrderCondition
                            {
                                IsMarket               = order.Type == _orderImit,
                                TakeProfitOffset       = (decimal?)order.TakeProfit,
                                StopLossOffset         = (decimal?)order.StopLoss,
                                UpperBound             = (decimal?)order.UpperBound,
                                LowerBound             = (decimal?)order.LowerBound,
                                TrailingStopLossOffset = order.TrailingStop,
                            };
                        }
                        else
                        {
                            orderType = order.Type == "market" ? OrderTypes.Market : OrderTypes.Limit;
                        }

                        SendOutMessage(new ExecutionMessage
                        {
                            OrderType     = orderType,
                            ExecutionType = ExecutionTypes.Order,
                            OrderId       = order.Id,
                            ServerTime    = order.Time.FromOanda(),
                            Price         = (decimal)order.Price,
                            Volume        = order.Units,
                            Side          = order.Side.To <Sides>(),
                            SecurityId    = order.Instrument.ToSecurityId(),
                            ExpiryDate    = order.Expiry == null ? (DateTimeOffset?)null : order.Expiry.Value.FromOanda(),
                            Condition     = condition,
                            PortfolioName = GetPortfolioName(accountId),
                        });
                    }

                    if (count < 50)
                    {
                        break;
                    }
                }

                int?maxTradeId = null;

                while (true)
                {
                    var trades = _restClient.GetTrades(accountId, maxTradeId);

                    var count = 0;

                    foreach (var trade in trades)
                    {
                        count++;

                        maxTradeId = trade.Id - 1;

                        var takeProfit  = Math.Abs(trade.TakeProfit) < 0.0000001 ? (decimal?)null : (decimal)trade.TakeProfit;
                        var stopLoss    = Math.Abs(trade.StopLoss) < 0.0000001 ? (decimal?)null : (decimal)trade.StopLoss;
                        var tralingStop = trade.TrailingStop == 0 ? (int?)null : trade.TrailingStop;

                        var isConditional = takeProfit != null || stopLoss != null || tralingStop != null;

                        var transId = TransactionIdGenerator.GetNextId();

                        SendOutMessage(new ExecutionMessage
                        {
                            ExecutionType         = ExecutionTypes.Order,
                            OrderType             = isConditional ? OrderTypes.Conditional : OrderTypes.Limit,
                            OrderId               = trade.Id,
                            OriginalTransactionId = transId,
                            ServerTime            = trade.Time.FromOanda(),
                            Price         = (decimal)trade.Price,
                            Volume        = trade.Units,
                            Balance       = 0,
                            Side          = trade.Side.To <Sides>(),
                            SecurityId    = trade.Instrument.ToSecurityId(),
                            OrderState    = isConditional ? OrderStates.Active : OrderStates.Done,
                            PortfolioName = GetPortfolioName(accountId),
                            Condition     = isConditional ? new OandaOrderCondition
                            {
                                TakeProfitOffset       = takeProfit,
                                StopLossOffset         = stopLoss,
                                TrailingStopLossOffset = tralingStop,
                            } : null,
                        });

                        if (!isConditional)
                        {
                            SendOutMessage(new ExecutionMessage
                            {
                                ExecutionType         = ExecutionTypes.Trade,
                                OrderId               = trade.Id,
                                OriginalTransactionId = transId,
                                TradeId               = trade.Id,
                                TradePrice            = (decimal)trade.Price,
                                Volume        = trade.Units,
                                ServerTime    = trade.Time.FromOanda(),
                                SecurityId    = trade.Instrument.ToSecurityId(),
                                PortfolioName = GetPortfolioName(accountId),
                            });
                        }
                    }

                    if (count < 50)
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>Коллбэк результата запроса списка заявок.</summary>
        /// <param name="portName">Имя портфеля.</param>
        /// <param name="data">Результат запроса списка заявок.</param>
        /// <param name="ex">Ошибка запроса списка заявок.</param>
        private void ClientOnOrdersData(string portName, List <Order> data, Exception ex)
        {
            if (ex != null)
            {
                SendOutError(ex);
                return;
            }

            foreach (var nativeOrder in data)
            {
                if (!IsOrderSupported(nativeOrder))
                {
                    continue;
                }

                var leg = nativeOrder.legDetails[0];

                var secId = new SecurityId
                {
                    SecurityCode = leg.symbolInfo.symbol,
                    BoardCode    = "EQ"
                };

                var transId = _ordersByTransactionId.TryGetKey(nativeOrder.orderId);
                if (transId == 0)
                {
                    transId = TransactionIdGenerator.GetNextId();
                    SaveOrder(transId, nativeOrder.orderId);
                }

                var tuple = _orderStateMap[nativeOrder.orderStatus];

                var msg = new ExecutionMessage
                {
                    SecurityId            = secId,
                    PortfolioName         = portName,
                    Side                  = leg.orderAction.ETradeActionToSide(),
                    Price                 = nativeOrder.limitPrice.To <decimal>(),
                    Volume                = leg.orderedQuantity.To <decimal>(),
                    Balance               = (leg.orderedQuantity - leg.filledQuantity).To <decimal>(),
                    OriginalTransactionId = transId,
                    OrderId               = nativeOrder.orderId,
                    ExecutionType         = ExecutionTypes.Order,
                    OrderType             = nativeOrder.priceType.ETradePriceTypeToOrderType(),
                    ServerTime            = ETradeUtil.ETradeTimestampToUTC(nativeOrder.orderExecutedTime > 0 ? nativeOrder.orderExecutedTime : nativeOrder.orderPlacedTime),
                    OrderState            = tuple.Item1,
                    OrderStatus           = tuple.Item2,
                };

                switch (msg.OrderType)
                {
                case OrderTypes.Limit:
                {
                    msg.Price = (decimal)nativeOrder.limitPrice;
                    break;
                }

                case OrderTypes.Conditional:
                {
                    if (nativeOrder.priceType == "STOP")
                    {
                        msg.Condition = new ETradeOrderCondition
                        {
                            StopType  = ETradeStopTypes.StopMarket,
                            StopPrice = (decimal)nativeOrder.stopPrice
                        };
                    }
                    else if (nativeOrder.priceType == "STOP_LIMIT")
                    {
                        msg.Condition = new ETradeOrderCondition
                        {
                            StopType  = ETradeStopTypes.StopLimit,
                            StopPrice = (decimal)nativeOrder.stopPrice
                        };
                        msg.Price = nativeOrder.limitPrice.To <decimal>();
                    }
                    else
                    {
                        this.AddErrorLog(LocalizedStrings.Str3374Params, nativeOrder.priceType);
                    }

                    break;
                }
                }

                SendOutMessage(msg);
            }
        }
        /// <inheritdoc />
        public override void SendInMessage(Message message)
        {
            if (message.IsBack)
            {
                if (message.Adapter == this)
                {
                    message.Adapter = null;
                    message.IsBack  = false;
                }
                else
                {
                    base.SendInMessage(message);
                    return;
                }
            }

            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_sync)
                {
                    if (!IsRestoreOnErrorReconnect)
                    {
                        ClearSubscribers();
                    }

                    _subscriptionRequests.Clear();
                    _passThroughtIds.Clear();
                }

                base.SendInMessage(message);
                break;
            }

            case MessageTypes.Disconnect:
            {
                var messages = new List <Message>();

                lock (_sync)
                {
                    messages.AddRange(_newsSubscribers.Values.Select(p => p.Message.Clone()));
                    messages.AddRange(_subscribers.Values.Select(p => p.Message.Clone()));
                    messages.AddRange(_pfSubscribers.Values.Select(p => p.Message.Clone()));

                    if (IsRestoreOnNormalReconnect)
                    {
                        _subscriptionRequests.AddRange(messages.Select(m => m.Clone()));
                    }
                    else
                    {
                        ClearSubscribers();
                    }
                }

                foreach (var msg in messages)
                {
                    if (msg is MarketDataMessage mdMsg)
                    {
                        mdMsg.OriginalTransactionId = mdMsg.TransactionId;
                        mdMsg.TransactionId         = TransactionIdGenerator.GetNextId();
                        mdMsg.IsSubscribe           = false;

                        if (IsRestoreOnNormalReconnect)
                        {
                            _passThroughtIds.Add(mdMsg.TransactionId);
                        }
                    }
                    else if (msg is PortfolioMessage pfMsg)
                    {
                        pfMsg.TransactionId = TransactionIdGenerator.GetNextId();
                        pfMsg.IsSubscribe   = false;

                        if (IsRestoreOnNormalReconnect)
                        {
                            _passThroughtIds.Add(pfMsg.TransactionId);
                        }
                    }

                    base.SendInMessage(msg);
                }

                base.SendInMessage(message);
                break;
            }

            case MessageTypes.MarketData:
                ProcessInMarketDataMessage((MarketDataMessage)message);
                break;

            case MessageTypes.Portfolio:
                ProcessInPortfolioMessage((PortfolioMessage)message);
                break;

            default:
                base.SendInMessage(message);
                break;
            }
        }
        /// <inheritdoc />
        public override void SendInMessage(Message message)
        {
            if (message.IsBack)
            {
                if (message.Adapter == this)
                {
                    message.IsBack = false;
                }
                else
                {
                    base.SendInMessage(message);
                    return;
                }
            }

            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_syncObject)
                {
                    _partialRequests.Clear();
                    _original.Clear();
                    _unsubscribeRequests.Clear();
                }

                break;
            }

            case MessageTypes.MarketData:
            {
                var mdMsg = (MarketDataMessage)message;

                if (mdMsg.IsSubscribe)
                {
                    var from = mdMsg.From;

                    if (from != null)
                    {
                        var length = (mdMsg.To ?? DateTimeOffset.Now) - from.Value;
                        var step   = InnerAdapter.GetHistoryStepSize(mdMsg, out var iterationInterval);

                        if (length > step)
                        {
                            var info = new DownloadInfo(this, (MarketDataMessage)mdMsg.Clone(), step, iterationInterval);

                            message = info.InitNext();

                            lock (_syncObject)
                            {
                                _original.Add(info.Origin.TransactionId, info);
                                _partialRequests.Add(info.CurrTransId, info);
                            }
                        }
                    }
                }
                else
                {
                    lock (_syncObject)
                    {
                        if (!_original.TryGetValue(mdMsg.OriginalTransactionId, out var info))
                        {
                            break;
                        }

                        var transId = TransactionIdGenerator.GetNextId();
                        _unsubscribeRequests.Add(transId, Tuple.Create(mdMsg.TransactionId, info));

                        mdMsg.OriginalTransactionId = info.CurrTransId;
                        mdMsg.TransactionId         = transId;
                    }
                }

                break;
            }

            case ExtendedMessageTypes.PartialDownload:
            {
                var partialMsg = (PartialDownloadMessage)message;

                lock (_syncObject)
                {
                    lock (_syncObject)
                    {
                        if (!_original.TryGetValue(partialMsg.OriginalTransactionId, out var info))
                        {
                            break;
                        }

                        var mdMsg = info.InitNext();

                        if (mdMsg.To == null)
                        {
                            _original.Remove(partialMsg.OriginalTransactionId);
                            _partialRequests.RemoveWhere(p => p.Value == info);
                        }
                        else
                        {
                            _partialRequests.Add(info.CurrTransId, info);
                        }

                        message = mdMsg;
                    }
                }

                break;
            }
            }

            base.SendInMessage(message);
        }
Example #24
0
        /// <summary>
        /// Отправить сообщение.
        /// </summary>
        /// <param name="message">Сообщение.</param>
        protected override void OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                _isHistoricalSubscribed = false;

                if (_session != null)
                {
                    try
                    {
                        _session.Stop();
                        _session.Logout(OnLogoutSuccess, OnLogoutFailure);
                    }
                    catch (Exception ex)
                    {
                        SendOutError(ex);
                    }

                    _session = null;
                }

                SendOutMessage(new ResetMessage());

                break;
            }

            case MessageTypes.Connect:
            {
                if (_session != null)
                {
                    throw new InvalidOperationException(LocalizedStrings.Str1619);
                }

                if (_api != null)
                {
                    throw new InvalidOperationException(LocalizedStrings.Str3378);
                }

                _isDownloadSecurityFromSite = IsDownloadSecurityFromSite;

                _api = new LmaxApi(IsDemo ? "https://web-order.london-demo.lmax.com" : "https://api.lmaxtrader.com");
                _api.Login(new LoginRequest(Login, Password.To <string>(), IsDemo ? ProductType.CFD_DEMO : ProductType.CFD_LIVE), OnLoginOk, OnLoginFailure);

                break;
            }

            case MessageTypes.Disconnect:
            {
                if (_session == null)
                {
                    throw new InvalidOperationException(LocalizedStrings.Str1856);
                }

                _session.Stop();
                _session.Logout(OnLogoutSuccess, OnLogoutFailure);
                _session = null;

                break;
            }

            case MessageTypes.PortfolioLookup:
            {
                ProcessPortfolioLookupMessage();
                break;
            }

            case MessageTypes.OrderStatus:
            {
                ProcessOrderStatusMessage();
                break;
            }

            case MessageTypes.Time:
            {
                _session.RequestHeartbeat(new HeartbeatRequest(TransactionIdGenerator.GetNextId().To <string>()), () => { }, CreateErrorHandler("RequestHeartbeat"));
                break;
            }

            case MessageTypes.OrderRegister:
            {
                ProcessOrderRegisterMessage((OrderRegisterMessage)message);
                break;
            }

            case MessageTypes.OrderCancel:
            {
                ProcessOrderCancelMessage((OrderCancelMessage)message);
                break;
            }

            case MessageTypes.SecurityLookup:
            {
                ProcessSecurityLookupMessage((SecurityLookupMessage)message);
                break;
            }

            case MessageTypes.MarketData:
            {
                ProcessMarketDataMessage((MarketDataMessage)message);
                break;
            }
            }
        }
Example #25
0
        private SubscriptionSecurityAllMessage CheckSubscription(ref Message message)
        {
            lock (_sync)
            {
                if (_parents.Count == 0)
                {
                    return(null);
                }

                if (message is ISubscriptionIdMessage subscrMsg && message is ISecurityIdMessage secIdMsg)
                {
                    foreach (var parentId in subscrMsg.GetSubscriptionIds())
                    {
                        if (_parents.TryGetValue(parentId, out var parent))
                        {
                            // parent subscription has security id (not null)
                            if (parent.Origin.SecurityId == secIdMsg.SecurityId)
                            {
                                return(null);
                            }

                            SubscriptionSecurityAllMessage allMsg = null;

                            if (!parent.Child.TryGetValue(secIdMsg.SecurityId, out var child))
                            {
                                allMsg = new SubscriptionSecurityAllMessage();

                                parent.Origin.CopyTo(allMsg);

                                allMsg.ParentTransactionId = parentId;
                                allMsg.TransactionId       = TransactionIdGenerator.GetNextId();
                                allMsg.SecurityId          = secIdMsg.SecurityId;

                                child = new ChildSubscription(allMsg.TypedClone());
                                child.Subscribers.Add(allMsg.TransactionId, child.Origin);

                                parent.Child.Add(secIdMsg.SecurityId, child);

                                allMsg.LoopBack(this, MessageBackModes.Chain);
                                _allChilds.Add(allMsg.TransactionId, RefTuple.Create(parentId, SubscriptionStates.Stopped));

                                this.AddDebugLog("New ALL map: {0}/{1} TrId={2}-{3}", child.Origin.SecurityId, child.Origin.DataType2, allMsg.ParentTransactionId, allMsg.TransactionId);
                            }

                            //var subscriptionIds = subscrMsg.GetSubscriptionIds().Where(i => i != parentId).Concat(child.Subscribers.Cache);
                            subscrMsg.SetSubscriptionIds(child.Subscribers.CachedKeys);

                            if (!child.State.IsActive())
                            {
                                child.Suspended.Add(message);
                                message = null;

                                this.AddDebugLog("ALL suspended: {0}/{1}, cnt={2}", child.Origin.SecurityId, child.Origin.DataType2, child.Suspended.Count);
                            }

                            return(allMsg);
                        }
                    }
                }
            }

            return(null);
        }
 public PointOfSaleServiceBuilder()
 {
     this.query     = new InMemoryItemRegistry();
     this.generator = new Mock <TransactionIdGenerator>().Object;
     this.display   = new Mock <Display>().Object;
 }