如何使用 LINQ 按时间间隔(OHLC 条)对时间序列进行分组

发布于 2024-11-03 13:59:33 字数 359 浏览 0 评论 0原文

我以前见过这个问题的不同版本,但没有明确的答案。

我有一个带有时间戳的对象列表(股票交易数据或“报价”):

Class Tick
{
  Datetime Timestamp;
  double Price;
}
  1. 我想根据按特定间隔分组的那些值生成另一个列表 创建 OHLC 柱(开盘价、最高价、最低价、收盘价)。 这些条可以是指定的任何间隔(1 分钟、5、10 甚至 1 小时)。

  2. 我还需要找到一种有效的方法将新的“刻度”排序到列表中,因为它们 可能会以高速率到达(每秒 3-5 个刻度)。

对此有任何想法将不胜感激,谢谢!

I've seen variation on this question before, but without a definite answer.

I have a list of object with a timestamp (stock trades data, or 'ticks'):

Class Tick
{
  Datetime Timestamp;
  double Price;
}
  1. I want to generate another list based on those values which is grouped by certain interval
    in order to create an OHLC bar (Open, High, Low, Close).
    These bars may be of any interval specified (1 minute, 5, 10 or even 1 hour).

  2. I also need to find an efficient way to sort new "ticks" into the list, as they
    may arrive at high rate (3-5 ticks per second).

Would appreciate any thoughts on this, Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静赏你的温柔 2024-11-10 13:59:33

我想生成另一个基于列表
那些按以下分组的值
一定的间隔,以创建
OHLC 柱(开盘价、最高价、最低价、收盘价)。
这些条可以是任意间隔的
指定(1 分钟、5 分钟、10 分钟甚至 1 分钟)
小时)。

不幸的是,您还没有指定:

  1. 柱状图系列的阶段是什么。
  2. 柱线的开始/结束时间是否纯粹基于“自然时间”(仅取决于固定时间表,而不取决于其中第一个和最后一个报价的时间戳)。

假设自然时间日内柱线,相位通常固定为午夜。因此,每小时的柱线将为 00:00 - 01:00、01:00 - 02:00 等。在这种情况下,柱线的开始/结束时间可以作为其唯一键。

那么问题就变成了:报价的时间戳属于哪个柱开始/结束时间?如果我们假设上面假设的一切,那么可以通过一些简单的整数数学轻松解决。然后,查询可以类似于(未经测试,仅算法):

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)
           };

通常希望通过索引/日期时间定位柱形图以及按时间顺序枚举系列中的所有柱形图。在这种情况下,您可能需要考虑将条形图存储在一个集合中,例如 SortedList(其中键是条形图的开始或结束时间),它将填充所有这些角色很好。

我还需要找到一个有效的方法
将新的“刻度”排序到列表中,如
他们可能会以很高的速度到达(3-5
每秒滴答数)。

这取决于你的意思。

如果这些价格变动来自实时喂价(按时间顺序),您根本不需要查找 - 只需存储当前的、不完整的“部分”柱线即可。当新的蜱虫到达时,检查它的时间戳。如果它仍然是当前“部分”柱的一部分,只需使用新信息更新柱(即 Close = tick.Price、High = Max(oldHigh、tick.Price) 等)。否则,“部分”栏已完成 - 将其推入您的栏集合中。请注意,如果您使用“自然时间”柱,则柱的结束也可能由时间的流逝而不是价格事件引起(例如,每小时的柱在整点完成)。

编辑:

否则,您需要进行查找。如果您将条形存储在排序列表中(按开始时间/结束时间作为键),就像我上面提到的那样,那么您只需要计算与关联的条形开始时间/结束时间一个勾。那应该很容易;我已经为您提供了如何在上面的 LINQ 查询中完成此操作的示例。

例如:

myBars[GetBeginTime(tick.Timestamp)].Update(tick);

I want to generate another list based
on those values which is grouped by
certain interval in order to create an
OHLC bar (Open, High, Low, Close).
These bars may be of any interval
specified (1 minute, 5, 10 or even 1
hour).

Unfortunately, you haven't specified:

  1. What the phase of the bar-series will be.
  2. Whether a bar's begin / end times are purely "natural-time" based (depend solely on a fixed schedule rather than on the timestamp of the first and last ticks in it) or not.

Assuming natural-time intra-day bars, the phases are usually clamped to midnight. So hourly bars will be 00:00 - 01:00, 01:00 - 02:00, etc. In this case, the begin / end-time of a bar can serve as its unique-key.

So then the problem becomes: To what bar- begin / end time does a tick's timestamp belong to? If we assume everything I've assumed above, that can be solved easily with some simple integer math. The query can then be something like (untested, algo only):

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)
           };

It's common to want to locate a bar by index / date-time as well as to enumerate all bars in a series chronologically. In this case, you might want to consider storing the bars in a collection such as a SortedList<DateTime, Bar> (where the key is a bar's begin or end time), which will fill all these roles nicely.

I also need to find an efficient way
to sort new "ticks" into the list, as
they may arrive at high rate (3-5
ticks per second).

It depends on what you mean.

If these ticks are coming off a live price-feed (chronologically), you don't need a look-up at all - just store the current, incomplete, "partial" bar. When a new tick arrives, inspect its timestamp. If it is still part of the current "partial" bar, just update the bar with the new information (i.e. Close = tick.Price, High = Max(oldHigh, tick.Price) etc.). Otherwise, the "partial" bar is done - push it into your bar-collection. Do note that if you are using "natural-time" bars, the end of a bar could also be brought on by the passage of time rather than by a price-event (e.g. an hourly bar completes on the hour).

EDIT:

Otherwise, you'll need to do a lookup. If you're storing in the bars in a sorted-list (keyed by begin-time / end-time) as I've mentioned above, then you'll just need to calculate the bar begin-time / end-time associated with a tick. That should be easy enough; I've already given you a sample of how you might accomplish that in the LINQ query above.

For example:

myBars[GetBeginTime(tick.Timestamp)].Update(tick);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文