Как я могу переписать этот блок 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, но я надеюсь, что этого повторения не будет. Я пытался использовать список с индексом, но запутался во всей этой сложности, потому что не знаю, как составить список условий и действий, а затем найти их.

Условно полиморфизму

GH DevOps 18.07.2024 16:02

Что делает SearchArray? Кажется немного странным, что в каждом случае задаются разные переменные. Откуда остальная часть кода узнает, имеет ли скажем dMAPriceLong допустимое значение?

JonasH 18.07.2024 16:15

SearchArray находит значение, наиболее близкое к текущей цене, это означает, что это действительная стратегия, которой следует следовать. В большинстве случаев остальные в любом случае равны нулю. Не все утверждения могут быть истинными одновременно.

Harold 18.07.2024 16:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
100
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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# или других функциональных языков для хранения формул и вычислений в более удобном для чтения виде.

bool lowStoEntryLongStrat => (conditional expression). И тут if (lowStoEntryLongStrat). Func<T> не нужен.
Robert Harvey 18.07.2024 16:32
Ответ принят как подходящий

Вы можете использовать список условий и соответствующих действий, чтобы сделать этот блок операторов 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.

Это хорошо. Зацикливается, если проверка и назначение действия напрямую. Также сохраняется использование переменных в моем исходном коде. Хороший, спасибо! (Я не могу проголосовать за это, потому что у меня недостаточно репутации, но я попробую именно этот)

Harold 18.07.2024 16:39

Очень хорошее решение, я часто использовал подобные шаблоны. Однако имейте в виду, что это может вызвать проблемы с производительностью при быстром выполнении; Я думаю, что лямбда-функции могут быть воссозданы при каждом вызове, если предположить, что они не оптимизированы для компилятора (исправимо путем перемещения стратегий за пределы области видимости и замены локальных значений функции локальными в лямбда-выражении (x, y, ...) => { }), а также удалением цепочки JMP, которая перемещает ее вверх на уровень абстракции, поэтому вы можете чаще обращаться к куче памяти, но я не совсем в этом уверен, поскольку не видел, чтобы нативный C пострадал от аналогичного использования анонимных функций.

Prime 18.07.2024 17:13

Другие вопросы по теме

Похожие вопросы