參考這一篇:「How to group a time series by interval (OHLC bars) with LINQ」。
我這裡使用 C#.NET 實作,並作了一些小小的修正,使之確實可以執行,並可從期交所所下載的原始 Tick 資料檔,經由前置的解壓縮、轉換為 Tick 物件型態,再透過該實作邏輯,就可以將 Tick 物件依所指定的時間週期 (time-interval),群組為所謂的「分K棒」(其實,正確的稱呼應該為 OHCK Bar)。
這裡也不禁對 LINQ 實作技術感到讚嘆! 它讓中間層 (middleware)的物件結構與資料來源 (data-sources)的存取,變得更為簡單太多了,所以也使得 Tick 轉K棒 的轉換邏輯,可以利用相當簡潔的語法 (類 SQL 語法),而達成該功能的實現。
底下的程式碼並未包含前述所提包括解壓縮、轉換為 Tick 物件等邏輯,只從一群已有 Tick 資料的 Collection 集合 (型態為 IEnumerable),依據所指定的 Interval 時間間隔,轉換為 K棒 (含開、高、收、低、量)的實作邏輯。
Tick 與 OHLC-Bar(K棒) 物件結構為:
public class Tick
{
public string Symbol { get; set; } //商品代號
public DateTime Timestamp { get; set; } //成交日期時間
public decimal Price { get; set; } //成交價格
public uint volume { get; set; } //成交量
}
public class OHLCBar
{
public string Symbol { get; set; } //商品代號
public decimal OPEN { get;set; } //開盤價
public decimal CLOSE { get; set; } //收盤價
public decimal HIGH { get; set; } //最高價
public decimal LOW { get; set; } //最低價
public uint VOLUME { get; set; } //成交量
public DateTime BeginTime { get; set; } //開始時間
public TimeSpan Interval { get; set; } //時間區間
}
將 Ticks 集合當成參數傳進該 method (generate_OHLCBar),處理後再傳回 OHLCBar 集合。
底下最精華的部分在於程式碼 21~29 行,這在傳統 SQL 語法是無法這樣寫出來的 (GroupBy 的欄位為變數),真的可以仔細玩味之該實作的技巧。
/** 將 Tick 資料依 Interval 時間間隔組成為 OHLC Bar.
* <param name="ticks">Ticks 型態的集合</param>
*/
private IEnumerable<OHLCBar> generate_OHLCBar(IEnumerable<Tick> ticks)
{
long barSizeInTicks = 5; //5 secs.
TimeSpan natural_time = new TimeSpan(8,45,0); //台指期開盤時間
var query =
from tick in ticks
//取得 TimeBar 的起始索引值, index 值必須為整數
let barIndexForDay =
Convert.ToInt32((tick.Timestamp.TimeOfDay.Subtract(natural_time)).TotalSeconds / barSizeInTicks)
// Calculate the begin-time of the bar associated with a tick.
// For example, turn 2011/04/28 14:23.45
// into 2011/04/28 14:20.00, assuming 5 min bars.
let barBeginDateTime =
tick.Timestamp.Date.Add(natural_time).AddSeconds(barIndexForDay * barSizeInTicks)
// Produce raw tick-data for each bar by grouping.
group tick by new { barBeginDateTime, tick.Symbol } into tickGroup
orderby tickGroup.Key.barBeginDateTime
// Order prices for a group chronologically.
let orderedPrices = tickGroup.OrderBy(t => t.Timestamp).Select(t => t.Price)
select new OHLCBar()
{
Symbol = tickGroup.Key.Symbol,
OPEN = orderedPrices.First(),
CLOSE = orderedPrices.Last(),
HIGH = orderedPrices.Max(),
LOW = orderedPrices.Min(),
BeginTime = tickGroup.Key.barBeginDateTime,
VOLUME= Convert.ToUInt32(tickGroup.Sum(t => t.volume))
};
return query;
}
請問這個有VB.NET的版本嗎?
大大你好,在建構論文研究需要使用的系統時,進行到設計tick資料轉檔功能google到您這篇文章,簡潔的程式碼卻可以達到如此的功能,趕到相當興奮,於是在我的程式中立刻新增了一個tick.cs,並將您的程式碼貼過去,但接著馬上就呆了,以下是我思考的流程,盼望大大提點 :
(在C#中)我已將期交所資料=>datatable=>處理(篩選契約,結算日)=>輸出datatable=>輸出datagridview(剩日期、契約、結算、成交時間、成交價格、成交量)=>於是我現在手上有一個dt物件是篩選好的tick資料型態,
接著我使用您所貼的方法,new了一個tick物件,new了一個OHLCBar物件,
想法上是將我原本的dt(tick)匯入tick物件,
然後使用private IEnumerable generate_OHLCBar(IEnumerable ticks)方法
得到OHLCBar物件,而我就可以在使用OHLCbar物件產生新的datagridview和畫K線,(以上是我的思考理解),但我卡關的地方在於,當我用for將dt載入對應的tick物件之後,我該怎麼使用這個方法呢?(方法的傳入和傳出部分有點看不懂,還請大大指示) 又,不曉得我上述的思考過程有誤嗎?
您好,剛剛試作了一下,感覺很棒。
不過第15行Convert.ToInt32感覺好像會四捨五入,
改成Math.Floor不知您的看法如何? 謝謝。
細節性的需求,可依自己的需求來調整囉。 ~