Как я могу переписать этот блок if/Else if в более структурированный, сжатый и оптимальный вид. (С#)

В С#.NET. Этот блок if/else if работает нормально, но его становится неудобно поддерживать и читать. Мне нужен более оптимизированный стиль письма.


if (Globals.SRSI < 10 && Globals.SRSI != 0 && Globals.ATR14 != 0) //Low Stochastic Entry Long Strategy
{ 
    dStochRSIPriceLong = markPrice - (0.1 * Globals.ATR14); 
    ECStrategy = "Stochastic Long"; 
} 
else if (Globals.RSI < 20 && Globals.RSI != 0 && Globals.ATR14 != 0) //RSI Rebound Long Strategy
{ 
    dRSIPriceLong = markPrice - (0.2 * Globals.ATR14); 
    ECStrategy = "Rebound Long"; 
}
else if (Globals.MACDLINEPrevious < Globals.MACDSigLINEPrevious && Globals.MACDLINE > Globals.MACDSigLINE) //MACD Crossover Long Strategy
{
    dMACDCrossoverLong = markPrice - (0.2 * Globals.ATR14);
    ECStrategy = "Crossover Long";
}
else if (Math.Abs(markPrice - Globals.SMA25) > 300 && Globals.PreviousCandleLo > Globals.SMA25 && markPrice > Globals.SMA25 && Globals.SMA25 > Globals.SMA50 && Globals.SMA50 > Globals.SMA100) //Runaway Long Strategy
{
    dLoCandleLong = Globals.PreviousCandleLo;
    ECStrategy = "Runaway Long";
}                                                                            
else if (markPrice > Globals.SMA25 && Globals.SMA25 > Globals.SMA50 && Globals.SMA50 > Globals.SMA100) //Knife Long Strategy
{ 
    dMA2PriceLong = Globals.SMA25; 
    ECStrategy = "Knife Long"; 
}  
else if (markPrice > Globals.SMA50 && Globals.SMA50 > Globals.SMA100) //Moving Average Momentum Long Strategy
{ 
    dMAPriceLong = Globals.SMA50; 
    ECStrategy = "Momentum Long"; 
}                               
else if (markPrice > Globals.SMA100) //MA100 Breakout Long Strategy
{ 
    dPullbacksPriceLong = Globals.SMA100; 
    ECStrategy = "Breakout Long"; 
}                                                      
dPositionEntryPriceLong = SearchArray(markPrice, new List<double> { dStochRSIPriceLong, dRSIPriceLong, dMACDCrossoverLong, dLoCandleLong, dMA2PriceLong, dMAPriceLong, dPullbacksPriceLong });


Очевидно, что еще будет if/else, но я надеюсь, что этого повторения не будет. Я пытался использовать список с индексом, но запутался во всей этой сложности, потому что не знаю, как составить список условий и действий, а затем найти их.

🤔 А знаете ли вы, что...
C# предоставляет средства для сериализации и десериализации данных.


100
3

Ответы:

Я бы предложил создать класс для каждой «стратегии»; циклический просмотр списка всех стратегий; и позволить каждому определить, применимо ли оно, и, если да, внести свой результат в список результатов. Затем интерпретируйте список или утвердите его размер 1.

interface IStrategy{
    bool IsApplicable(Globals globals);
    Result result(Globals globals);
}

class StochasticLongStrategy: IStrategy{
    bool IsApplicable(Globals globals){
        return Globals.SRSI < 10 && Globals.SRSI != 0 && Globals.ATR14 != 0;
    }
    Result result(Globals globals){
        return Result(.....)
    }
}


List<IStrategy> strategies = {new StochasticLongStrategy(),..........}
List<Result> strategyResults = new();

foreach (IStrategy strategy in strategies) {
    if (strategy.IsApplicable(globals)) strategyResults.Add(strategy.Result(globals))
}

......interpret strategyResults here

Вы можете следовать этому шаблону, чтобы отделить свои «правила» от логического потока приложения.

Я не переписывал весь ваш код, потому что если вы используете этот подход, чтобы сделать свой код более выразительным и читабельным, то то, как вы называете функции, действительно важно.

// strategies / functions / rules
Func<bool> lowStoEntryLongStrat = () => Globals.SRSI < 10 && Globals.SRSI != 0 && Globals.ATR14 != 0;
Func<bool> rsiREboundLongStrat = () => Globals.RSI < 20 && Globals.RSI != 0 && Globals.ATR14 != 0;

// procedure
if (lowStoEntryLongStrat()) //Low Stochastic Entry Long Strategy
{
    dStochRSIPriceLong = markPrice - (0.1 * Globals.ATR14);
    ECStrategy = "Stochastic Long";
}
else if (rsiREboundLongStrat()) //RSI Rebound Long Strategy
{
    dRSIPriceLong = markPrice - (0.2 * Globals.ATR14);
    ECStrategy = "Rebound Long";
}
// ...

Вам также следует рассмотреть возможность использования F# или других функциональных языков для хранения формул и вычислений в более удобном для чтения виде.


Решено

Вы можете использовать список условий и соответствующих действий, чтобы сделать этот блок операторов if/else более структурированным, сжатым и простым в обслуживании. Этого можно добиться, создав список кортежей или собственный класс для хранения условия и действия, а затем пройдя по этому списку. Вот один из способов сделать это, используя собственный класс:

public class Strategy
{
    public Func<bool> Condition { get; set; }
    public Action Action { get; set; }
}

public void DetermineStrategy(double markPrice)
{
    double dStochRSIPriceLong = 0, dRSIPriceLong = 0, dMACDCrossoverLong = 0;
    double dLoCandleLong = 0, dMA2PriceLong = 0, dMAPriceLong = 0, dPullbacksPriceLong = 0;
    string ECStrategy = string.Empty;

    var strategies = new List<Strategy>
    {
        new Strategy
        {
            Condition = () => Globals.SRSI < 10 && Globals.SRSI != 0 && Globals.ATR14 != 0,
            Action = () => { dStochRSIPriceLong = markPrice - (0.1 * Globals.ATR14); ECStrategy = "Stochastic Long"; }
        },
        new Strategy
        {
            Condition = () => Globals.RSI < 20 && Globals.RSI != 0 && Globals.ATR14 != 0,
            Action = () => { dRSIPriceLong = markPrice - (0.2 * Globals.ATR14); ECStrategy = "Rebound Long"; }
        },
        new Strategy
        {
            Condition = () => Globals.MACDLINEPrevious < Globals.MACDSigLINEPrevious && Globals.MACDLINE > Globals.MACDSigLINE,
            Action = () => { dMACDCrossoverLong = markPrice - (0.2 * Globals.ATR14); ECStrategy = "Crossover Long"; }
        },
        new Strategy
        {
            Condition = () => Math.Abs(markPrice - Globals.SMA25) > 300 && Globals.PreviousCandleLo > Globals.SMA25 && markPrice > Globals.SMA25 && Globals.SMA25 > Globals.SMA50 && Globals.SMA50 > Globals.SMA100,
            Action = () => { dLoCandleLong = Globals.PreviousCandleLo; ECStrategy = "Runaway Long"; }
        },
        new Strategy
        {
            Condition = () => markPrice > Globals.SMA25 && Globals.SMA25 > Globals.SMA50 && Globals.SMA50 > Globals.SMA100,
            Action = () => { dMA2PriceLong = Globals.SMA25; ECStrategy = "Knife Long"; }
        },
        new Strategy
        {
            Condition = () => markPrice > Globals.SMA50 && Globals.SMA50 > Globals.SMA100,
            Action = () => { dMAPriceLong = Globals.SMA50; ECStrategy = "Momentum Long"; }
        },
        new Strategy
        {
            Condition = () => markPrice > Globals.SMA100,
            Action = () => { dPullbacksPriceLong = Globals.SMA100; ECStrategy = "Breakout Long"; }
        }
    };

    foreach (var strategy in strategies)
    {
        if (strategy.Condition())
        {
            strategy.Action();
            break;
        }
    }

    dPositionEntryPriceLong = SearchArray(markPrice, new List<double> { dStochRSIPriceLong, dRSIPriceLong, dMACDCrossoverLong, dLoCandleLong, dMA2PriceLong, dMAPriceLong, dPullbacksPriceLong });
}
  1. Класс Strategy инкапсулирует условие и действие.
  2. Создается список объектов Strategy, каждый из которых содержит условие и соответствующее действие.
  3. Метод DefinStrategy проходит по списку и выполняет действие первой стратегии, условие которой выполнено.

Такой подход упрощает обслуживание и чтение условий и действий. Вы можете добавлять, удалять или изменять стратегии, не меняя структуру метода DefinStrategy.