Closed Hulkstance closed 3 years ago
The following snippet only checks close and open prices. You may expand it to make more complex logic assuming you already calculated ema indicators
var buy = df.Rows.Select(kvp => {
var sr = kvp.Value.As<float>();
var open = sr.Get("Open");
var close = sr.Get("Close");
return open > close ? 1.0 : 0.0;
});
df.AddColumn("Buy", buy);
@zyzhu, thanks for your answer. By following your way,
kvp.Value.GetAs<decimal>("Rsi")
returns Deedle.MissingValueException: 'Value at the key Rsi is missing'
because the values are probably <missing>
and not filled with zeroes.
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe['close'], timeperiod=2)
return dataframe
def informative_pairs(self):
informative_pairs = []
return informative_pairs
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['rsi'] < 45
& (dataframe['rsi'] > dataframe['rsi'].shift(1))),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(dataframe['rsi'].gt(70)),
'sell'] = 0
return dataframe
Item1
is not descriptive.csharp
var buy = a.ZipInner(b).Select(kvp => kvp.Value.Item1 < 45 && kvp.Value.Item1 > kvp.Value.Item2);
You may either fill missing first or use TryGet
to get an OptionalValue
. Then check it like the following. The actual logic is up to you.
var buy = df.Rows.Select(kvp => {
var sr = kvp.Value.As<float>();
var open = sr.TryGet("Open");
var close = sr.TryGet("Close");
return open.HasValue && close.HasValue && open.Value > close.Value ? 1.0 : 0.0;
});
df.AddColumn("Buy", buy);
@zyzhu, it seems like I need to use the Zip anyway. This looks good? P.S. I don't want to use TryGet because it's not generic.
public override Frame<int, string> PopulateIndicators(Frame<int, string> df)
{
var candles = df.Rows.Select(kvp => new Ohlcv
{
Timestamp = kvp.Value.GetAs<DateTime>("Timestamp"),
Open = kvp.Value.GetAs<decimal>("Open"),
High = kvp.Value.GetAs<decimal>("High"),
Low = kvp.Value.GetAs<decimal>("Low"),
Close = kvp.Value.GetAs<decimal>("Close"),
Volume = kvp.Value.GetAs<decimal>("Volume")
}).Observations.Select(e => e.Value).ToList<IOhlcv>();
df.AddColumn("Rsi", candles.Rsi(2));
return df;
}
public override Frame<int, string> PopulateBuyTrend(Frame<int, string> df)
{
var a = df.GetColumn<decimal>("Rsi").Realign(Enumerable.Range(0, df.RowCount)).FillMissing(0m);
var b = df.GetColumn<decimal>("Rsi").Shift(1).Realign(Enumerable.Range(0, df.RowCount)).FillMissing(0m);
var buy = a.ZipInner(b).Select(kvp =>
{
var rsi = kvp.Value.Item1;
var rsiShifted = kvp.Value.Item2;
return rsi < 45 && rsi > rsiShifted;
});
df.AddColumn("Buy", buy);
return df;
}
public override Frame<int, string> PopulateSellTrend(Frame<int, string> df)
{
var a = df.GetColumn<decimal>("Rsi").Realign(Enumerable.Range(0, df.RowCount)).FillMissing(0m);
var sell = a.Select(kvp =>
{
var rsi = kvp.Value;
return rsi > 70;
});
df.AddColumn("Sell", sell);
return df;
}
That looks good. Just one feedback. You may return buy or sell series
directly instead of adding it into the df
so that you can keep the original df
intact. If "Buy" column exists in df
already the next time you run it, AddColumn
will throw error.
@zyzhu, thanks a lot! :)
I'm recreating this from python (pandas). I'm new to the library and I'd like to have a feedback, if something could be done better. And @zyzhu, thanks for your examples on SO and here in the issues, By the way, the strategy differs from the python code, but the idea stays.
I don't think
ZipInner
is the most human-readable way to represent the following. It would be nice if you know a better way.Full code