从方法中仅向用户公开重要逻辑

Exposing only important logic to the user from a method

RsiStrategy 是一个 class 应该由用户修改,所以它适合他的愿望。有那个循环,例如。 if (i < StartupCandleCount - 1) 暴露给用户,不是很好,因为用户不关心它。用户关心的,是指标人口和buy/sell条件。你们能给我一些解决方法吗?

public interface IStrategy
{
    IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<Ohlcv> candles);
}

public abstract class StrategyBase : IStrategy
{
    public abstract IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<Ohlcv> candles);
}

public class RsiStrategy : StrategyBase
{
    public override IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<Ohlcv> candles)
    {
        var result = new List<TradeAdvice>();

        var rsiPeriod = 4;
        var rsi = candles.Rsi(rsiPeriod);

        for (int i = 0; i < candles.Count; i++)
        {
            if (i < StartupCandleCount - 1)
                result.Add(TradeAdvice.WarmupData);
            else if (rsi[i] < 45 && rsi[i] > rsi[i - 1])
                result.Add(TradeAdvice.Buy);
            else if (rsi[i] > 70)
                result.Add(TradeAdvice.Sell);
            else
                result.Add(TradeAdvice.NoAction);
        }

        return result;
    }
}

预计

我期待类似下面的内容和关于 if (i < StartupCandleCount - 1) 的逻辑,并且该循环可能应该移至摘要 class。

private void PopulateIndicators()
{
    var rsi = candles.Rsi(14);
    var ema = candles.Ema(6);

    // these have to be returned somehow
}

// TODO: I could of course pass current and previous item to the method,
// but I want to be access anything, e.g. rsi[i - 42]. That's basically shifting right
public void BuyCondition()
{
    return rsi[i] < 45 && rsi[i] > rsi[i - 1])
}

public void SellCondition()
{
    return rsi[i] > 70;
}

一种可能的解决方案是让所有策略实现来自 StrategyBasepublic abstract TradeAdvice Advise(IReadOnlyList<Ohlcv> candles, int index);

的抽象方法

StrategyBase 将生成预热数据交易建议,运行 循环用于其余部分并为每个项目调用 Advise。每个策略都将只实现这个 Advise 方法,而 Prepare 应该只由 StrategyBase 实现。

使用 index 参数,策略知道它为哪个项目提供建议。

如果在循环 运行 之前需要一些准备工作,应该有一个 protected abstract void StrategyBase.Prepare 方法。但是接口的方法应该重命名为 RunExecute 之类的东西。所以:

public interface IStrategy
{
    IReadOnlyList<TradeAdvice> Execute(IReadOnlyList<Ohlcv> candles);
}

public abstract class StrategyBase : IStrategy
{
    protected abstract void Prepare(IReadOnlyList<Ohlcv> candles);
    protected abstract TradeAdvice Advise(int index);
    
    public IReadOnlyList<TradeAdvice> Execute(IReadOnlyList<Ohlcv> candles)
    {
        // Call Prepare once, fill up WarmupData, call Advise once per the rest of the items
    }
}

public class RsiStrategy : StrategyBase
{
    protected override void Prepare(IReadOnlyList<Ohlcv> candles)
    {
        // Calculate rsi and save it and all the rest to class fields
    }
    
    protected override TradeAdvice Advise(int index)
    {
        // return advice using index and class fields
    }
}