如何通过 LINQ 将一个列表转换为另一个半聚合列表?

发布于 2024-08-31 20:52:33 字数 1359 浏览 6 评论 0原文

我是 Linq 初学者,所以只是想找人告诉我是否可以使用 Linq 实现以下内容,如果可以的话,请提供一些如何实现它的指示。

我想将一个金融时间序列列表转换为另一个列表,其中第二个系列列表的长度将与第一个列表相同或更短(通常它会更短,即,它成为一个新列表,其中元素本身代表一个列表的信息聚合)或第一个列表中的更多元素)。如何将列表从一个列表折叠到另一个列表取决于第一个列表中的数据。该算法需要跟踪在将新元素添加到第二个列表时重置的计算。举个例子可能更容易描述:

表1(收盘价和成交量从开始到结束的时间序列):

{P=7,V=1}, {P=10,V=2}, {P= 10,V=1}, {P=10,V=3}, {P=11,V=5}, {P=12,V=1}, {P=13,V=2}, {P= 17,V=1}, {P=15,V=4}, {P=14,V=10}, {P=14,V=8}, {P=10,V=2}, {P= 9,V=3}, {P=8,V=1}

列表 2(一系列开盘/收盘价格范围以及该范围期间的交易量总和,使用这 2 个参数设置将列表 1 转换为列表 2:参数 1:价格范围步长 = 3,参数 2:价格范围反转步长 = 6):

{O=7,C=10,V=1+2+1}, {O=10,C=13,V=3+ 5+1+2}, {O=13,C=16,V=0}, {O=16,C=10,V=1+4+10+8+2}, {O=10,C= 8,V=3+1}

在列表 2 中,我明确地显示了列表 2 中列表 1 中 V 属性的总和。但 V 只是一个 long,所以实际上它只是一个数字。所以它的工作原理是开盘时间序列价格为 7。然后我们从这个初始起始价格中寻找第一个价格,其中 delta 距离 7 为 3(通过参数 1 设置)。在列表 1 中,当我们浏览列表时,下一步是向上移动到 10,因此我们已经建立了“上升趋势”。因此,现在我们在列表 2 中构建第一个元素,开盘价=7,收盘价=10,并对第一个列表中使用的所有柱的交易量求和,以达到列表 2 中的第一步。现在,下一个元素的起点是 10。建立另一个向上台阶,我们需要再向上推进 3 个以创建另一个向上台阶,或者我们可以反向并向下前进 6 个(参数 2)。使用列表 1 中的数据,我们首先达到 13,这样就构建了列表 2 中的第二个元素,并对用于到达此步骤的所有 V 属性求和。我们继续这个过程直到列表 1 处理结束。

请注意列表 1 中发生的间隙跳跃。我们仍然想要创建一个 {O=13,C=16,V=0} 的步骤元素。 V 为 0 只是说明我们有一个经过此步骤的范围移动,但成交量为 0(此处没有出现列表 1 中的实际价格 - 它位于其上方,但我们想要构建导致价格的一组步骤那是在它上面)。

列表 2 中倒数第二个条目表示从上到下的反转。

列表 2 中的最后一个条目仅使用列表 1 中的最终关闭,即使它实际上尚未完成建立全范围步骤。

感谢您提供有关如何通过 Linq 完成此操作(如果有的话)的任何指示。

I'm a Linq beginner so just looking for someone to let me know if following is possible to implement with Linq and if so some pointers how it could be achieved.

I want to transform one financial time series list into another where the second series list will be same length or shorter than the first list (usually it will be shorter, i.e., it becomes a new list where the elements themselves represent aggregation of information of one or more elements from the 1st list). How it collapses the list from one to the other depends on the data in the first list. The algorithm needs to track a calculation that gets reset upon new elements added to second list. It may be easier to describe via an example:

List 1 (time ordered from beginning to end series of closing prices and volume):

{P=7,V=1}, {P=10,V=2}, {P=10,V=1}, {P=10,V=3}, {P=11,V=5}, {P=12,V=1}, {P=13,V=2}, {P=17,V=1}, {P=15,V=4}, {P=14,V=10}, {P=14,V=8}, {P=10,V=2}, {P=9,V=3}, {P=8,V=1}

List 2 (series of open/close price ranges and summation of volume for such range period using these 2 param settings to transform list 1 to list 2: param 1: Price Range Step Size = 3, param 2: Price Range Reversal Step Size = 6):

{O=7,C=10,V=1+2+1}, {O=10,C=13,V=3+5+1+2}, {O=13,C=16,V=0}, {O=16,C=10,V=1+4+10+8+2}, {O=10,C=8,V=3+1}

In list 2, I explicitly am showing the summation of the V attributes from list 1 in list 2. But V is just a long so it would just be one number in reality. So how this works is opening time series price is 7. Then we are looking for first price from this initial starting price where delta is 3 away from 7 (via param 1 setting). In list 1, as we move thru the list, the next step is upwards move to 10 and thus we've established an "up trend". So now we build our first element in list 2 with Open=7,Close=10 and sum up the Volume of all bars used in first list to get to this first step in list 2. Now, next element starting point is 10. To build another up step, we need to advance another 3 upwards to create another up step or we could reverse and go downwards 6 (param 2). With data from list 1, we reach 13 first, so that builds our second element in list 2 and sums up all the V attributes used to get to this step. We continue on this process until end of list 1 processing.

Note the gap jump that happens in list 1. We still want to create a step element of {O=13,C=16,V=0}. The V of 0 is simply stating that we have a range move that went thru this step but had Volume of 0 (no actual prices from list 1 occurred here - it was above it but we want to build the set of steps that lead to price that was above it).

Second to last entry in list 2 represents the reversal from up to down.

Final entry in list 2 just uses final Close from list 1 even though it really hasn't finished establishing full range step yet.

Thanks for any pointers of how this could be potentially done via Linq if at all.

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

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

发布评论

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

评论(1

孤独患者 2024-09-07 20:52:33

我的第一个想法是,为什么要尝试使用 LINQ 来解决这个问题?使用 yield 关键字来部分处理然后吐出答案来创建新的 Enumerable 似乎是一个更好的情况。

大概是这样的:

public struct PricePoint
{
    ulong price;
    ulong volume;
}

public struct RangePoint
{
    ulong open;
    ulong close;
    ulong volume;
}

public static IEnumerable<RangePoint> calculateRanges(IEnumerable<PricePoint> pricePoints)
{
    if (pricePoints.Count() > 0)
    {
        ulong open = pricePoints.First().price;
        ulong volume = pricePoints.First().volume;

        foreach(PricePoint pricePoint in pricePoints.Skip(1))
        {
            volume += pricePoint.volume;
            if (pricePoint.price > open)
            {
                if ((pricePoint.price - open) >= STEP)
                {
                    // We have established a up-trend.
                    RangePoint rangePoint;
                    rangePoint.open = open;
                    rangePoint.close = close;
                    rangePoint.volume = volume;

                    open = pricePoint.price;
                    volume = 0;

                    yield return rangePoint;
                }
            }
            else
            {
                if ((open - pricePoint.price) >= REVERSAL_STEP)
                {
                    // We have established a reversal.
                    RangePoint rangePoint;
                    rangePoint.open = open;
                    rangePoint.close = pricePoint.price;
                    rangePoint.volume = volume;

                    open = pricePoint.price;
                    volume = 0;

                    yield return rangePoint;
                }
            }
        }

        RangePoint lastPoint;
        lastPoint.open = open;
        lastPoint.close = pricePoints.Last().price;
        lastPoint.volume = volume;
        yield return lastPoint;
    }
}

这还没有完成。例如,它不处理间隙,并且存在未处理的边缘情况,其中最后一个数据点可能会被消耗,但它仍然会处理“lastPoint”。但这应该足以开始。

My first thought is, why try to use LINQ on this? It seems like a better situation for making a new Enumerable using the yield keyword to partially process and then spit out an answer.

Something along the lines of this:

public struct PricePoint
{
    ulong price;
    ulong volume;
}

public struct RangePoint
{
    ulong open;
    ulong close;
    ulong volume;
}

public static IEnumerable<RangePoint> calculateRanges(IEnumerable<PricePoint> pricePoints)
{
    if (pricePoints.Count() > 0)
    {
        ulong open = pricePoints.First().price;
        ulong volume = pricePoints.First().volume;

        foreach(PricePoint pricePoint in pricePoints.Skip(1))
        {
            volume += pricePoint.volume;
            if (pricePoint.price > open)
            {
                if ((pricePoint.price - open) >= STEP)
                {
                    // We have established a up-trend.
                    RangePoint rangePoint;
                    rangePoint.open = open;
                    rangePoint.close = close;
                    rangePoint.volume = volume;

                    open = pricePoint.price;
                    volume = 0;

                    yield return rangePoint;
                }
            }
            else
            {
                if ((open - pricePoint.price) >= REVERSAL_STEP)
                {
                    // We have established a reversal.
                    RangePoint rangePoint;
                    rangePoint.open = open;
                    rangePoint.close = pricePoint.price;
                    rangePoint.volume = volume;

                    open = pricePoint.price;
                    volume = 0;

                    yield return rangePoint;
                }
            }
        }

        RangePoint lastPoint;
        lastPoint.open = open;
        lastPoint.close = pricePoints.Last().price;
        lastPoint.volume = volume;
        yield return lastPoint;
    }
}

This isn't yet complete. For instance, it doesn't handle gapping, and there is an unhandled edge case where the last data point might be consumed, but it will still process a "lastPoint". But it should be enough to get started.

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