我以前见过关于这个问题的不同版本,但是没有一个明确的答案。
我有一个带有时间戳(股票交易数据,或'ticks')的对象列表:
Class Tick
{
Datetime Timestamp;
double Price;
}
我想根据这些值生成另一个列表,这些值按一定的间隔分组以创建OHLC条(Open, High, Low, Close)。这些条形图可以是指定的任意间隔(1分钟、5分钟、10分钟甚至1小时)。
我还需要找到一种有效的方法来将新的"tick"排序到列表中,因为它们
希望对此有任何想法,谢谢!
我想生成另一个基于对这些值进行分组一定的间隔,以便创建一个OHLC条(开、高、低、关)。这些小节可以是任意间隔的指定(1分钟、5分钟、10分钟甚至1分钟)小时)。
遗憾的是,您没有指定:
- bar系列的相位是什么
- 条的开始/结束时间是否纯粹基于"自然时间"(仅依赖于固定的时间表,而不是其中第一个和最后一个刻度的时间戳)。
假设在自然时间内,相位通常夹紧到午夜。所以小时酒吧是00:00 - 01:00,01:00 - 02:00,等等。在这种情况下,bar的开始/结束时间可以作为它的唯一键。
那么问题就变成了:一个tick的时间戳属于哪个bar- begin/end时间?如果我们假设我上面所假设的一切,那么用一些简单的整数数学就可以很容易地解决这个问题。查询可以是这样的(未经测试,仅限算法):
var bars = from tick in ticks
// Calculate the chronological, natural-time, intra-day index
// of the bar associated with a tick.
let barIndexForDay = tick.Timestamp.TimeOfDay.Ticks / 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.AddTicks
(barIndexForDay * barSizeInTicks)
// Produce raw tick-data for each bar by grouping.
group tick by barBeginDateTime into tickGroup
// Order prices for a group chronologically.
let orderedPrices = tickGroup.OrderBy(t => t.Timestamp)
.Select(t => t.Price)
select new Bar
{
Open = orderedPrices.First(),
Close = orderedPrices.Last(),
High = orderedPrices.Max(),
Low = orderedPrices.Min(),
BeginTime = tickGroup.Key,
EndTime = tickGroup.Key.AddTicks(barSizeInTicks)
};
通常希望通过索引/日期-时间来定位bar,并按时间顺序枚举一系列中的所有bar。在这种情况下,您可能想要考虑将bar存储在一个集合中,例如SortedList<DateTime, Bar>
(其中的键是bar的开始或结束时间),这将很好地满足所有这些角色。
我还需要找到一个有效的方法将新的"勾号"排序到列表中,如它们可能会以很高的速率到达(3-5)
这取决于你的意思。
如果这些刻度来自实时价格反馈(按时间顺序),您根本不需要查找-只需存储当前的,不完整的,"部分"条。当一个新的tick到达时,检查它的时间戳。如果它仍然是当前"部分"条形图的一部分,只需用新信息更新条形图(即Close = tick)。Price, High = Max(oldHigh, tick.Price)等)。否则,"部分"栏就完成了-将其推入您的栏集。请注意,如果你使用的是"自然时间"柱状图,则柱状图的结束也可能是由时间的流逝而不是由价格事件引起的(例如,小时柱状图在整点完成)。
编辑:否则,您将需要进行查找。如果您在排序列表中存储栏(按begin-time/end-time键),那么您只需要计算与tick相关的栏begin-time/end-time。这应该很容易;我已经给出了一个示例,说明如何在上面的LINQ查询中实现这一点。
例如:myBars[GetBeginTime(tick.Timestamp)].Update(tick);