Как преобразовать один список в другой полуагрегированный список через LINQ? - PullRequest
1 голос
/ 11 мая 2010

Я новичок в 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 я явно показываю суммирование атрибутов V из списка 1 в списке 2. Но V - это просто длинное число, поэтому в действительности это будет просто одно число. Итак, как это работает, цена временного ряда открытия равна 7. Затем мы ищем первую цену из этой начальной стартовой цены, где дельта находится в 3 от 7 (через установку параметра 1). В списке 1, когда мы перемещаемся по списку, следующим шагом является движение вверх к 10, и поэтому мы установили «восходящий тренд». Итак, теперь мы строим наш первый элемент в списке 2 с Open = 7, Close = 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, если вообще.

1 Ответ

1 голос
/ 11 мая 2010

Моя первая мысль: зачем пытаться использовать LINQ на этом? Кажется, лучше создать новый Enumerable с использованием ключевого слова yield для частичной обработки, а затем выплевывания ответа.

Что-то вроде этого:

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». Но для начала этого должно быть достаточно.

...