public void AddPendingItem(SourceQuotation quotation)
 {
     lock (this._WaitQueue)
     {
         this._WaitQueue.Enqueue(quotation);
     }
 }
 public AbnormalInstrument(SourceQuotation firstAbnormalItem, AbnormalQuotationManager abnormalQuotationManager, PriceRangeCheckRule priceRangeCheckRule)
 {
     this._InstrumentId = firstAbnormalItem.InstrumentId;
     this._TimeoutCount = 0;
     this._WaitQueue = new Queue<SourceQuotation>();
     this._WaitQueue.Enqueue(firstAbnormalItem);
     this._AbnormalQuotationManager = abnormalQuotationManager;
     this._PriceRangeCheckRule = priceRangeCheckRule;
 }
 public bool AppendPendingItem(SourceQuotation quotation)
 {
     lock (this._WaitQueue)
     {
         if (this._WaitQueue.Count > 0)
         {
             this._WaitQueue.Enqueue(quotation);
             return true;
         }
     }
     return false;
 }
        public void SetAbnormalInfo(SourceQuotation quotation)
        {
            GeneralQuotation last;
            quotation.IsAbnormal = false;
            if (this._LastQuotationManager.LastAccepted.TryGetLastQuotation(quotation.InstrumentId, out last))
            {
                PriceRangeCheckRule rule = this._PriceRangeCheckRules[quotation.InstrumentId];
                double diff = 0;
                double oldPrice = 0;
                switch (rule.OutOfRangeType)
                {
                    case OutOfRangeType.Ask:
                        diff = Math.Abs(quotation.Ask - last.Ask);
                        oldPrice = last.Ask;
                        break;
                    case OutOfRangeType.Bid:
                        diff = Math.Abs(quotation.Bid - last.Bid);
                        oldPrice = last.Bid;
                        break;
                    default:
                        Logger.AddEvent(TraceEventType.Error, "AbnormalQuotationManager.IsNormalPrice unknown OutOfRangeType:{0}", rule.OutOfRangeType.ToString());
                        break;
                }

                // diff to diffPoints
                int decimalPlace = MainService.QuotationManager.ConfigMetadata.Instruments[quotation.PrimitiveQuotation.InstrumentId].DecimalPlace;
                int diffPoints = (int)(Math.Round(diff * Math.Pow(10, decimalPlace), 0));

                quotation.IsAbnormal = diffPoints > rule.ValidVariation;
                if (quotation.IsAbnormal)
                {
                    quotation.DiffPoints = diffPoints;
                    quotation.OldPrice = oldPrice;
                    quotation.OutOfRangeType = rule.OutOfRangeType;
                    quotation.WaitSeconds = rule.OutOfRangeWaitTime;
                    quotation.ConfirmId = this.GetNextConfirmId();
                }
            }
        }
 public void Set(SourceQuotation quotation)
 {
     Dictionary<int, SourceQuotation> sourceQuotations;
     if (!this._LastReceivedQuotations.TryGetValue(quotation.SourceId, out sourceQuotations))
     {
         sourceQuotations = new Dictionary<int, SourceQuotation>();
         this._LastReceivedQuotations.Add(quotation.SourceId, sourceQuotations);
     }
     sourceQuotations[quotation.InstrumentId] = quotation;
 }
        public bool SetQuotation(SourceQuotation quotation)
        {
            bool isNormalAndNotWaiting = false;
            AbnormalInstrument abnormalInstrument;

            bool hasAbnormalInstrument = this._AbnormalInstruments.TryGetValue(quotation.InstrumentId, out abnormalInstrument);

            if (hasAbnormalInstrument)
            {
                if (abnormalInstrument.AppendPendingItem(quotation))
                {
                    return false;
                }
            }

            this.SetAbnormalInfo(quotation);
            if (quotation.IsAbnormal)
            {
                if (!this._PriceRangeCheckRules[quotation.InstrumentId].DiscardOutOfRangePrice)
                {
                    MainService.ExchangeManager.SwitchPriceEnableState(quotation.InstrumentId, false);
                    if (hasAbnormalInstrument)
                    {
                        abnormalInstrument.AddPendingItem(quotation);
                    }
                    else
                    {
                        abnormalInstrument = new AbnormalInstrument(quotation, this, this._PriceRangeCheckRules[quotation.InstrumentId]);
                        this._AbnormalInstruments.Add(quotation.InstrumentId, abnormalInstrument);
                    }
                    this.StartConfirm(quotation);
                }
            }
            else
            {
                isNormalAndNotWaiting = true;
            }

            return isNormalAndNotWaiting;
        }
        public void StartConfirm(SourceQuotation quotation)
        {
            string format = "F" + MainService.QuotationManager.ConfigMetadata.Instruments[quotation.InstrumentId].DecimalPlace;
            AbnormalQuotationMessage message = new AbnormalQuotationMessage();
            message.ConfirmId = quotation.ConfirmId;
            message.InstrumentId = quotation.InstrumentId;
            message.InstrumentCode = quotation.InstrumentCode;
            message.NewPrice = quotation.OutOfRangeType == OutOfRangeType.Ask ? quotation.Ask.ToString(format) : quotation.Bid.ToString(format);
            message.OldPrice = quotation.OldPrice;
            message.OutOfRangeType = quotation.OutOfRangeType;
            message.DiffPoints = quotation.DiffPoints;
            message.WaitSeconds = quotation.WaitSeconds;
            MainService.ClientManager.Dispatch(message);

            quotation.WaitEndTime = DateTime.Now.AddSeconds(quotation.WaitSeconds + 1);  // Add one sencond at server side.
            this.ChangeWaitTime(quotation.WaitEndTime);
        }
        public void ProcessQuotation(PrimitiveQuotation primitiveQuotation)
        {
            bool inverted;
            if (this._ConfigMetadata.EnsureIsKnownQuotation(primitiveQuotation, out inverted))
            {
                double ask, bid;
                if (this._LastQuotationManager.LastReceived.Fix(primitiveQuotation, out ask, out bid))
                {
                    if (this._LastQuotationManager.LastReceived.IsNotSame(primitiveQuotation))
                    {
                        MainService.ClientManager.Dispatch(new PrimitiveQuotationMessage() { Quotation = primitiveQuotation });

                        string instrumentCode = this._ConfigMetadata.Instruments[primitiveQuotation.InstrumentId].Code;
                        SourceQuotation quotation = new SourceQuotation(primitiveQuotation, ask, bid, instrumentCode, inverted);

                        if (this._SourceController.QuotationArrived(quotation))
                        {
                            // quotation come from Active Source and adjusted
                            if (this._AbnormalQuotationManager.SetQuotation(quotation))
                            {
                                // quotation is normal
                                this.ProcessNormalQuotation(quotation);
                            }
                        }
                        this._LastQuotationManager.LastReceived.Set(quotation);
                    }
                }
            }
            else
            {
                Logger.AddEvent(TraceEventType.Warning, "Discarded price:[ask={0}, bid={1}] got for {2} from {3}",
                    primitiveQuotation.Ask, primitiveQuotation.Bid, primitiveQuotation.Symbol, primitiveQuotation.SourceName);
            }
        }
        public void ProcessNormalQuotation(SourceQuotation quotation)
        {
            List<GeneralQuotation> quotations = new List<GeneralQuotation>();
            this._DerivativeController.Derive(quotation.Quotation, quotations);
            for (int i = 0; i < quotations.Count; i++)
            {
                quotations[i].OriginCode = this._ConfigMetadata.Instruments[quotations[i].InstrumentId].Code;
            }
            quotations.Add(quotation.Quotation);

            // adjust quotation according to adjuestment on instrument
            foreach (GeneralQuotation gq in quotations)
            {
                Instrument instrument = this._ConfigMetadata.Instruments[gq.InstrumentId];
                gq.Ask += CommonHelper.GetAdjustValue(instrument.AdjustPoints, instrument.DecimalPlace);
                gq.Bid += CommonHelper.GetAdjustValue(instrument.AdjustPoints, instrument.DecimalPlace);
            }
            this._LastQuotationManager.LastAccepted.Accept(quotations);

            MainService.ExchangeManager.AddQuotations(quotations);
            MainService.ClientManager.Dispatch(new QuotationsMessage() { Quotations = quotations });
        }
        //public TimeSpan ActiveSourceTimeoutSpan
        //{
        //    get
        //    {
        //        return this._ActiveSource.TimeoutSpan;
        //    }
        //}
        //public DateTime ActiveSourceTimeoutTime
        //{
        //    get
        //    {
        //        return this._ActiveSource.TimeoutTime;
        //    }
        //}
        public bool QuotationArrived(SourceQuotation quotation)
        {
            if (this._Instrument.IsSwitchUseAgio.Value)
            {
                this._AgioCalculator.QuotationArrived(quotation);
            }

            if (quotation.SourceId == this._ActiveSource.Id)
            {
                this._ActiveSource.QuotationArrived();
            }
            else
            {
                if (this._Relations[quotation.SourceId].IsDefault || !this._Relations[this._ActiveSource.Id].IsDefault && this._Relations[quotation.SourceId].Priority > this._Relations[this._ActiveSource.Id].Priority)
                {
                    // 如果价格来自优先级高的源,则切换到该源;
                    this.SwitchActiveSource(quotation.SourceId);
                }
                else if (this._ActiveSource.IsTimeout)
                {
                    // 如果当前源Timeout,来一个价格就向该源切换;
                    this.SwitchActiveSource(quotation.SourceId);
                }
            }

            if (quotation.SourceId == this._ActiveSource.Id)
            {
                // calculate price and adjust
                if (this._Instrument.UseWeightedPrice.Value)
                {
                    WeightedPriceRule rule = MainService.QuotationManager.ConfigMetadata.WeightedPriceRules[this._Instrument.Id];
                    quotation.Ask = (quotation.Ask * rule.AskAskWeight + quotation.Bid * rule.BidAskWeight + (quotation.Last.HasValue ? quotation.Last.Value * rule.AskLastWeight : 0) + (quotation.Ask + quotation.Bid) / 2 * rule.AskAverageWeight + (double)rule.AskAdjust) * (double)rule.Multiplier;
                    quotation.Bid = (quotation.Ask * rule.BidAskWeight + quotation.Bid * rule.BidBidWeight + (quotation.Last.HasValue ? quotation.Last.Value * rule.BidLastWeight : 0) + (quotation.Ask + quotation.Bid) / 2 * rule.BidAverageWeight + (double)rule.BidAdjust) * (double)rule.Multiplier;
                }
                quotation.Ask += this._Agio + CommonHelper.GetAdjustValue(this._Relations[quotation.SourceId].AdjustPoints, this._Instrument.DecimalPlace);
                quotation.Bid += this._Agio + CommonHelper.GetAdjustValue(this._Relations[quotation.SourceId].AdjustPoints, this._Instrument.DecimalPlace);

                this._LastActiveTime = DateTime.Now;
                if (!this.IsActive)
                {
                    MainService.ExchangeManager.SwitchPriceEnableState(this._Instrument.Id, true);
                    this.IsActive = true;
                }
                return true;
            }
            else
            {
                return false;
            }
        }
 public bool QuotationArrived(SourceQuotation quotation)
 {
     // do not lock _SourceInstruments here for performance, so we should judge if the instrument existed in _SourceInstruments. because of maybe in adding Instrument progress.
     if (this._SourceInstruments.ContainsKey(quotation.InstrumentId))
     {
         return this._SourceInstruments[quotation.InstrumentId].QuotationArrived(quotation);
     }
     else
     {
         return false;
     }
 }
        public void QuotationArrived(SourceQuotation quotation)
        {
            // remove expired sample data
            DateTime cutOffTime = DateTime.Now - this._MonitorTimeSpan;
            Queue<SourceQuotation> sampleQueue = this._QuotationSamples[quotation.SourceId];
            while (sampleQueue.Count > 0)
            {
                SourceQuotation q = sampleQueue.Peek();
                if (q.Timestamp < cutOffTime)
                {
                    sampleQueue.Dequeue();
                }
                else
                {
                    break;
                }
            }

            // add new sample
            sampleQueue.Enqueue(quotation);

            // calculate average price
            lock (this._AveragePrices)
            {
                if (sampleQueue.Count > this._LeastTicks)
                {
                    this._AveragePrices[quotation.SourceId] = sampleQueue.Average(q => q.Bid);
                }
                else
                {
                    this._AveragePrices[quotation.SourceId] = null;
                }
            }
        }