移动和滚动窗口后填充第一个缺失的空元素 我的代码C#

问题描述

我正在用 pandas 重新创建一个在 python 中制定的策略。我认为我的代码有效,即使我还没有比较这些值,因为我得到了一个例外。基本上,问题在于 .Shift(20) 删除了前 20 个元素,而 .Window(12 * 60 / 15) 删除了 47 个元素。认情况下,典型价格为 10180。在移动和滚动窗口之后,它们变成了 10113。我尝试使用 .FillMissing(),但它似乎没有将第一个空值附加到系列中。

enter image description here

def populate_indicators(self,dataframe: DataFrame,Metadata: dict) -> DataFrame:
    if not {'buy','sell'}.issubset(dataframe.columns):
        dataframe.loc[:,'buy'] = 0
        dataframe.loc[:,'sell'] = 0
    dataframe['typical'] = qtpylib.typical_price(dataframe)
    dataframe['typical_sma'] = qtpylib.sma(dataframe['typical'],window=10)
    min = dataframe['typical'].shift(20).rolling(int(12 * 60 / 15)).min()
    max = dataframe['typical'].shift(20).rolling(int(12 * 60 / 15)).max()
    dataframe['daily_mean'] = (max+min)/2
    return dataframe

我的代码(C#)

public override List<TradeAdvice> Prepare(List<OHLCV> candles)
{
    var result = new List<TradeAdvice>();

    var typicalPrice = candles.TypPrice().Select(e => e ?? 0).ToList();
    var typicalSma = typicalPrice.Sma(10);

    var series = typicalPrice.Toordinalseries();

    var min = series.Shift(20).Window(12 * 60 / 15).Select(kvp => kvp.Value.Min()).FillMissing(); // 10113 elements / 10180 expected
    var max = series.Shift(20).Window(12 * 60 / 15).Select(kvp => kvp.Value.Max()).FillMissing(); // 10113 elements / 10180 expected

    var dailyMean = (max + min) / 2;

    var asd = dailyMean.SelectValues(e => Convert.ToDecimal(e)).Values.ToList();
    var crossedBelow = asd.CrossedBelow(typicalPrice);
    var crossedAbove = asd.CrossedAbove(typicalPrice);

    for (int i = 0; i < candles.Count; i++)
    {
        if (i < StartupCandleCount - 1)
            result.Add(TradeAdvice.WarmupData);
        else if (crossedBelow[i]) // crossBelow is 10113 elements instead of 10180...
            result.Add(TradeAdvice.Buy);
        else if (crossedAbove[i]) // crossBelow is 10113 elements instead of 10180...
            result.Add(TradeAdvice.Sell);
        else
            result.Add(TradeAdvice.NoAction);
    }

    return result;
}

public class OHLCV
{
    public DateTime Timestamp { get; set; }
    public decimal Open { get; set; }
    public decimal High { get; set; }
    public decimal Low { get; set; }
    public decimal Close { get; set; }
    public decimal Volume { get; set; }
}

解决方法

如果你有一个用 ToOrdinalSeries 创建的序数系列,这意味着该系列的索引将自动生成从 0 到你的系列长度 - 1 的数值。但是,这仍然是一个真实的当您使用 Shift 等操作时,index 和 Deedle 会保留映射。

如果您的索引是一个日期,例如 01/01 => a,02/01 => b,03/01 => c,那么 Shift 会移动值并删除不再需要的键,即您可能会得到 02/01 => a,03/01 => b

它与序数索引的工作原理相同,因此如果您有 0 => a,1 => b,2 => c 并移动数据,您将得到类似 1 => a,2 => b 的内容。

如果您随后想要获得 0 => <default>,1 => a,2 => b,那么您可以使用 Realign 来完成此操作,它采用您想要跟随的新键列表 FillMissing。例如:

var ts = new[] { 0,1,2,3,4,5,6,7,8,9 }.ToOrdinalSeries();

var mins = ts.Shift(2).Window(2).Select(kvp => kvp.Value.Min());
var realigned = mins.Realign(Enumerable.Range(0,10)).FillMissing(-1); 

ts.Print();        // Starts from key '0' 
mins.Print();      // Starts from key '3' because of Shift & Window
realigned.Print(); // Starts from key '0' with three -1 values at the start