예제 #1
0
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="timeframe">ForexConnect timeframe descriptor</param>
            internal TimeframeItem(O2GTimeframe timeframe)
            {
                mTimeframe = timeframe;
                DateTime start = DateTime.Now.AddDays(-1), end = DateTime.Now;

                // parse the timeframe ID to get Quotes Manager timeframe descriptor
                if (!CandlePeriod.parsePeriod(timeframe.ID, ref mTimeframeUnit, ref mTimeframeLength))
                {
                    throw new ArgumentException("Invalide timeframe", "timeframe");
                }

                // get a candle in that timeframe to get it length
                CandlePeriod.getCandle(DateTime.Now, ref start, ref end, mTimeframeUnit, mTimeframeLength, 0, 0);
                mLength = end.Subtract(start);
            }
        /// <summary>
        /// Handling one tick
        /// </summary>
        /// <param name="offer"></param>
        private void HandleOffer(IOffer offer)
        {
            lock (mPeriods)
            {
                // calculate the start time of the period to which the tick belong to
                DateTime start = DateTime.MinValue, end = DateTime.MinValue;

                // calculate candle in EST time because the trading day is always closed by New York time
                // so to avoid handling different hour depending on daylight saying time - use EST always
                // for candle calculations

                // NOTE: for real application this part can be optimized. The candle calculation
                // is quite complex process, so it is better to avoid it when it is not actually required.
                // the way to optimize it is to keep end time of the period and check whether the tick belongs to
                // the period using the following condition start <= tick < end
                // so the calculation of new candle will be used only when tick is actually >= of the end
                // of the current candle.
                CandlePeriod.getCandle(mController.UtcToEst(offer.LastUpdate), ref start, ref end, mTimeframeUnit, mTimeframeLength, mTradingDayOffset, -1);
                start = mController.EstToUtc(start);
                // calculate the serial number of minute (for easier comparing)
                long currMinute = DateToMinute(offer.LastUpdate);

                if (mPeriods.Count == 0)
                {
                    // if here is no data in the collection yet - just add a dummy candle
                    mPeriods.Add(new Period(start, offer.Bid, offer.Ask, offer.MinuteVolume));
                    mLastMinute       = currMinute;
                    mLastMinuteVolume = offer.MinuteVolume;
                }
                else
                {
                    // otherwise get the most recent candle
                    Period period = mPeriods[mPeriods.Count - 1];
                    if (period.Time == start)
                    {
                        // if tick belongs to that period...

                        // update the latest (close) price of bid and ask bars
                        period._Ask.Close = offer.Ask;
                        period._Bid.Close = offer.Bid;

                        // if tick higher than high value of bars - update
                        if (period._Ask.High < offer.Ask)
                        {
                            period._Ask.High = offer.Ask;
                        }
                        if (period._Bid.High < offer.Bid)
                        {
                            period._Bid.High = offer.Bid;
                        }

                        // if tick lower than low value of bars - update
                        if (period._Ask.Low > offer.Ask)
                        {
                            period._Ask.Low = offer.Ask;
                        }
                        if (period._Bid.Low > offer.Bid)
                        {
                            period._Bid.Low = offer.Bid;
                        }

                        // here is a trick.
                        // we don't receive EVERY tick, so we can't simply count them.
                        // It is not a problem for calculating open, high, low and close, because
                        // the tick filter keeps every first, last, and the current extremum ticks
                        // In order to make the volume calculation also correct, the server
                        // broadcasts the accumulated tick volume for the current minute.

                        // so, if the tick belongs to the same minute as the previous tick -
                        // we must substract previous accumulated volume and add a new value.
                        // If the tick is the first tick of a new minute - we must simply
                        // add new accumulated value.
                        if (mLastMinute == currMinute)
                        {
                            period.Volume -= mLastMinuteVolume;
                            period.Volume += offer.MinuteVolume;
                        }
                        else if (currMinute > mLastMinute)
                        {
                            period.Volume += offer.MinuteVolume;
                        }

                        mLastMinute       = currMinute;
                        mLastMinuteVolume = offer.MinuteVolume;
                    }
                    else if (period.Time < start)
                    {
                        // this is a first tick of new period, simply create this period

                        // please pay attention that we don't use the first tick as an open
                        // value but use the previous close instead.
                        // This is how the current system works by default.

                        // soon, here should be an option to use the first tick for the open
                        // price instead.
                        mPeriods.Add(period = new Period(start, period.Bid.Close, period.Ask.Close, offer.MinuteVolume));

                        // update the latest (close) price of bid and ask bars
                        period._Ask.Close = offer.Ask;
                        period._Bid.Close = offer.Bid;

                        // if tick higher than high value of bars - update
                        if (period._Ask.High < offer.Ask)
                        {
                            period._Ask.High = offer.Ask;
                        }
                        if (period._Bid.High < offer.Bid)
                        {
                            period._Bid.High = offer.Bid;
                        }

                        // if tick lower than low value of bars - update
                        if (period._Ask.Low > offer.Ask)
                        {
                            period._Ask.Low = offer.Ask;
                        }
                        if (period._Bid.Low > offer.Bid)
                        {
                            period._Bid.Low = offer.Bid;
                        }

                        mLastMinute       = currMinute;
                        mLastMinuteVolume = offer.MinuteVolume;
                    }
                    else
                    {
                        // yep, it is possible that tick is older than the last candle.
                        // it may happen because we start to collect ticks actually BEFORE
                        // we sent the request to the server. So on the border of the minute
                        // it is possible that we "catch" some ticks of the previous
                        // minute

                        // so, simply ignore them
                        ;
                    }
                }
            }
        }