/// <summary> /// 請求商品歷史資料 /// </summary> /// <param name="e">資料請求事件</param> protected internal override void Request(DataRequestEvent e) { InstrumentDataRequest cDataRequest = this.DataRequest; DateTime[] cRanges = e.Ranges; ZRequest cRequest = new ZRequest(); cRequest.Method = "POST"; cRequest.Url = __sHttpUrl; cRequest.Parameters = string.Format("exchange={0}&symbolId={1}&timeFrame={2}&position={3}&startDate={4}&endDate={5}&count={6}", cDataRequest.Exchange, cDataRequest.Symbol, cDataRequest.Resolution.TotalSeconds, this.Position, cRanges[0].ToString("yyyy-MM-dd"), cRanges[1].ToString("yyyy-MM-dd"), e.Count); cRequest.CookieContainer = __cCookies; int iRet = cRequest.Request(); if (iRet == 0) { ZReader cReader = new ZReader(cRequest.Response); e.Result = cReader.Result; if (cReader.Result == 0) { int iCount = e.Count = cReader.Count; this.AdjustSize(iCount); ZBuffer cBuffer = cReader.Read(); while (--iCount >= 0) { cBuffer.Position = iCount * DATA_BLOCK_SIZE; DateTime cDate = cBuffer.GetDateTime(); double dOpen = cBuffer.GetDouble(); double dHigh = cBuffer.GetDouble(); double dLow = cBuffer.GetDouble(); double dClose = cBuffer.GetDouble(); double dVolume = cBuffer.GetDouble(); this.AddSeries(cDate, dOpen, dHigh, dLow, dClose, dVolume); } this.Position = cReader.Position; e.Ranges[0] = cReader.BeginDate; e.Ranges[1] = cReader.EndDate; if (this.Position == 0) { e.IsAlreadyRequestAllData = true; } } } }
private void SeriesSymbolData_onRequest(object sender, DataRequestEvent e) { SeriesSymbolData cTargetSeries = sender as SeriesSymbolData; if (!cTargetSeries.DataRequest.Range.IsAlreadyRequestAllData) { int iTotalSeconds = cTargetSeries.DataRequest.Resolution.TotalSeconds; SeriesSymbolData cBaseSeries = GetSeries(((iTotalSeconds < Resolution.MAX_BASE_TOTALSECONDS) ? Resolution.MIN_BASE_TOTALSECONDS : Resolution.MAX_BASE_TOTALSECONDS)); if (cBaseSeries.DataRequest.Range.IsAlreadyRequestAllData) { e.IsAlreadyRequestAllData = true; e.Count = cBaseSeries.DataRequest.Range.Count / e.Rate; } else { DataRequestEvent cRequestEvent = null; lock (__oLock) { //需要鎖定資源(因為有可能多個策略同時請求基礎序列類別資料, 如果不鎖定會重複請求資料) if (e.Totals == 0) { //檢查是否資料總個數為0(0=使用 InstrumentDataRequest 請求歷史資料) cRequestEvent = e.Clone(); //直接複製 } else { //如果不為0(表示使用者取得資料時超過目前已下載歷史資料的區間, 經過基礎週期比率計算之後再向伺服器請求歷史資料) int iTotals = e.Totals * e.Rate; //資料總個數 * 縮放比率 = 基礎週期需要請求的資料總個數 int iRequestCount = iTotals - cBaseSeries.DataRequest.Range.Count; //計算後的資料總個數 - 基礎週期目前已下載後的資料個數 = 欲請求的的個數 cRequestEvent = new DataRequestEvent(iRequestCount, iTotals, cBaseSeries.DataRequest.Resolution.Rate); } cBaseSeries.OnRequest(cRequestEvent); //回補歷史資訊 } if (cRequestEvent.Result == 0) { e.Result = cRequestEvent.Result; e.Ranges = cRequestEvent.Ranges; e.Count = cRequestEvent.Count / e.Rate; e.IsAlreadyRequestAllData = cRequestEvent.IsAlreadyRequestAllData; } } if (e.IsAlreadyRequestAllData) { //如果已經全部讀取完畢就取消事件 cTargetSeries.RemoveRequest(); } lock (__oLock) { //須鎖定資源(將基礎序列資料合併至目標序列時需要鎖定, 避免合併的時候多執行緒導致合併資料產生問題) int iTargetCount = cTargetSeries.Indexer.Count; int iAllocSize = e.Count - cTargetSeries.DataRequest.Range.Count; if (iTargetCount == 0 || iAllocSize > 0) { if (iAllocSize > 0) { ++iAllocSize; //多預留一個空間(避免陣列空間不足) cTargetSeries.AdjustSize(iAllocSize, true); } cBaseSeries.Merge(cTargetSeries); //合併資料 } } } }
internal void OnRequest(DataRequestEvent e) { if (onRequest != null) { onRequest(this, e); if (e.Result == 0) { __cDataRequest.Range.Count = e.Count; __cDataRequest.Range.From = e.Ranges[0]; __cDataRequest.Range.IsAlreadyRequestAllData = e.IsAlreadyRequestAllData; if (!this.Initialized) { //尚未初始化之前才需要更新(初始化之後已經併入即時報價資訊, 更新時間會是目前最新的報價時間) __cUpdateTime = __cTimes[this.Indexer.RealtimeIndex]; //更新最後的更新時間(如果沒有即時報價資訊, 這個就是最後一根 Bars 的時間) } if (onRequestCompleted != null) { onRequestCompleted(this, EventArgs.Empty); } } else { RemoveRequest(); //請求失敗就移除請求事件(表示可能伺服器有問題或沒有歷史報價資訊無法執行請求服務) } } }
private void SeriesSymbolData_onRequest(object sender, DataRequestEvent e) { int iCount = e.Count; DataRequest cDataRequest = __cSeries.DataRequest.Range; int iBaseCount = cDataRequest.Count; bool bRequest = e.Totals > iBaseCount; if (!bRequest) { bRequest = (__cDevice.Position == -1) ? true : e.CheckRequest(cDataRequest); } if (bRequest) { __cDevice.Request(e); if (e.Result == 0) { e.Count += iBaseCount; if (e.IsAlreadyRequestAllData) { __cSeries.RemoveRequest(); //如果已經全部讀取完畢就取消事件 if (onCompleted != null) { InstrumentDataRequest cInstDataRequest = __cSeries.DataRequest; onCompleted(this, new DataAdapterCompleteEvent(cInstDataRequest.Symbol, cInstDataRequest.Resolution.TotalSeconds)); } } } } else { e.Result = 0; e.Count = iBaseCount; e.Ranges = new DateTime[] { cDataRequest.From, cDataRequest.To }; e.IsAlreadyRequestAllData = cDataRequest.IsAlreadyRequestAllData; } }
private SeriesSymbolDataRand InternalGetSeries(InstrumentDataRequest dataRequest, bool useCache) { SeriesStorage cStorage = null; string sLSymbolId = dataRequest.Symbol.ToLower(); lock (__cStorages) { if (!__cStorages.TryGetValue(sLSymbolId, out cStorage)) { cStorage = new SeriesStorage(16); __cStorages.Add(sLSymbolId, cStorage); } } SeriesSymbolDataRand cSeriesRand = null; int iTotalSeconds = dataRequest.Resolution.TotalSeconds; if (useCache) { //是否使用快取 lock (cStorage) { //需要 lock 這個區塊(避免非同步讀取資料時發生問題) int iBaseSeconds = (iTotalSeconds < Resolution.MAX_BASE_TOTALSECONDS) ? Resolution.MIN_BASE_TOTALSECONDS : Resolution.MAX_BASE_TOTALSECONDS; SeriesSymbolData cSeries = cStorage.GetSeries(iTotalSeconds); if (cSeries == null) { cSeries = cStorage.GetSeries(iBaseSeconds); if (cSeries == null) { DataAdapter cAdapter = LoadAdapter(ref dataRequest); cSeries = cAdapter.Series; cStorage.Add(cSeries); } } if (iBaseSeconds == iTotalSeconds) { dataRequest = cSeries.DataRequest; goto exit; } else { cSeries = cSeries.CreateSeries(dataRequest); //利用基礎周期建立其他的資料周期 cStorage.Add(cSeries); //加入至 SeriesStorage } dataRequest.Resolution = cSeries.DataRequest.Resolution; //將目標的週期結構更新至傳入的 InstrumentDataRequest 週期結構 DataRequestEvent cRequestEvent = new DataRequestEvent(dataRequest); cSeries.OnRequest(cRequestEvent); //如果已經存在則請求使用者需要的歷史資料區間(請求方法會檢查目前已下載的歷史資料區間是否足夠, 如果使用者需要的歷史資料區間比較大會向伺服器請求) dataRequest.Range.Count = cRequestEvent.Count; //將請求後的正確數量傳入至結構內 exit: cSeriesRand = new SeriesSymbolDataRand(cSeries, dataRequest); } } else { DataAdapter cAdapter = LoadAdapter(ref dataRequest, false); //重新建立新的基礎週期序列資料(不使用快取, 不保存至快取內, 使用完畢之後立即 Dispose) SeriesSymbolData cSeries = cAdapter.Series; //取得新的基礎周期序列資料 int iBaseSeconds = (iTotalSeconds < Resolution.MAX_BASE_TOTALSECONDS) ? Resolution.MIN_BASE_TOTALSECONDS : Resolution.MAX_BASE_TOTALSECONDS; if (iBaseSeconds == iTotalSeconds) { dataRequest = cSeries.DataRequest; } else { SeriesSymbolData cTargetSeries = cSeries.CreateSeries(dataRequest); //使用 InstrumentDataRequest 建立新的其他週期序列資料 cSeries.Merge(cTargetSeries); //將基礎周期序列資料合併至新的其他週期序列資料 cSeries.Dispose(); //釋放基礎周期序列資料 cSeries = cTargetSeries; } cSeriesRand = new SeriesSymbolDataRand(cSeries, dataRequest); cStorage.Add(cSeries, true); //保存序列資料(存放在 SeriesStorage 內的序列資料才會自動合併最新的即時資訊報價) cAdapter.Dispose(); //釋放資料配置者類別 } return cSeriesRand; }
/// <summary> /// 請求商品歷史資料 /// </summary> /// <param name="e">資料請求事件</param> protected internal abstract void Request(DataRequestEvent e);