Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve stability propagation #1141

Open
sgflt opened this issue Apr 5, 2024 · 7 comments · May be fixed by #1148
Open

Improve stability propagation #1141

sgflt opened this issue Apr 5, 2024 · 7 comments · May be fixed by #1148
Labels
enhancement Issue describing or discussing an enhancement for this library

Comments

@sgflt
Copy link
Contributor

sgflt commented Apr 5, 2024

Is your feature request related to a problem? Please describe.
BaseStrategy should not be directly aware about stability. Stability is a function of used rules and indicators.
As user I have no clue about possible instabilities of used indicators and rules, therefore instability of strategy should be calculated at runtime from used rules.

Describe the solution you'd like
Drop unstableBars field from BaseStrategy and introduce isStableAt(int index) method to Rule.

F.E.:

public class DownTrendRule extends AbstractRule {

  private static final int UNSTABLE_BARS = 5;

  private final ADXIndicator directionStrengthIndicator;
  private final Rule downtrendRule;


  public DownTrendRule(final BarSeries series) {
    this.directionStrengthIndicator = new ADXIndicator(series, UNSTABLE_BARS);

    final var plusDMIndicator = new PlusDMIndicator(series);
    final var minusDMIndicator = new MinusDMIndicator(series);
    this.downtrendRule = new UnderIndicatorRule(plusDMIndicator, minusDMIndicator);
  }


  @Override
  public boolean isSatisfied(final int index) {
    return this.directionStrengthIndicator.getValue(index).isGreaterThan(numOf(25))
           && this.downtrendRule.isSatisfied(index)
  }
}

There is no way how to propagate stability to strategy.

@sgflt sgflt added the enhancement Issue describing or discussing an enhancement for this library label Apr 5, 2024
@sgflt
Copy link
Contributor Author

sgflt commented Apr 5, 2024

Related question #1142

@sgflt
Copy link
Contributor Author

sgflt commented Apr 5, 2024

If I consider following implementation:

public class DownTrendIndicator extends AbstractIndicator<Boolean> {

  private static final int UNSTABLE_BARS = 5;

  private final ADXIndicator directionStrengthIndicator;
  private final Rule downtrendRule;


  public DownTrendIndicator(final BarSeries series) {
    super(series);
    this.directionStrengthIndicator = new ADXIndicator(series, UNSTABLE_BARS);

    final var plusDMIndicator = new PlusDMIndicator(series);
    final var minusDMIndicator = new MinusDMIndicator(series);
    this.downtrendRule = new UnderIndicatorRule(plusDMIndicator, minusDMIndicator);
  }



  @Override
  public Boolean getValue(final int index) {
    return  this.directionStrengthIndicator.getValue(index).isGreaterThan(numOf(25))
            && this.downtrendRule.isSatisfied(index);
  }


  @Override
  public int getUnstableBars() {
    return UNSTABLE_BARS;
  }
}

Still, BaseStrategy have to be manually filled with unstableBars, which as user, I do not know where to get.

Related to #919

@sgflt
Copy link
Contributor Author

sgflt commented Apr 6, 2024

If propagation through rules to strategy is not viable, then I am thinking about user friendly builder, which does the dirty work.

StrategyBuilder.create()
   .withIndicators(List<Indicator>)    // Takes max unstable bars
   .withEntryRule(Rule)
   .withExitRule(Rule)
   .build() // calls new BaseStrategy(entry, exit, unstableBars)
   ;

@sgflt sgflt linked a pull request Apr 14, 2024 that will close this issue
5 tasks
@TheCookieLab
Copy link
Member

Regarding your builder example, the Strategy should only need to know about its two Rules and not the Indicators they use.

An Indicator knows it's own unstable period. If we are returning NaN for any calculation within the unstable period then Rules don't need to know about the unstable period either as it can simply key off of NaN values. Typically Rules are comparing the results of one or more Indicators and if any of them are NaN it should know what to do.

@sgflt
Copy link
Contributor Author

sgflt commented May 10, 2024

If NaN is used as unstable marker, it should be used consistently. But for example SMA returns estimates in unstable period. As contra argument, returning NaN inside unstable period cannot be distinguised from returning NaN within stable period that is caused by corrupted data or some zero division bug.

In PoC #1148 I have opted in for explicit isStable method to allow indicators return any value that is based on partial computation and that should not be used for decision.

@Override
public boolean isStable() {
return this.processedBars >= this.barCount && this.indicator.isStable();
}

Assuming Rule and Strategy have now stability property too and are aware of underlying indicators stability.

default boolean shouldEnter(final TradingRecord tradingRecord) {
return isStable() && getEntryRule().isSatisfied(tradingRecord);
}

@TheCookieLab
Copy link
Member

See #947

@sgflt
Copy link
Contributor Author

sgflt commented May 20, 2024

#947 (comment)

This sums up concern about NaN. If NaN could be correct value within unstable period, each indicator have to handle NaN.

If we return normal numbers, indicators fixes automatically after some period of time without any NaN checking ifs.

   // boilerplate
   var value = nestedIndicator.getValue();
   var value2 = nestedIndicator2.getValue();
   if (value.isNan() || value2.isNan()) {
      return NaN;
   }

Another example.

  // sma is unusable 10 bars, 5 inner sma returns NaN, +5 NaN from outer sma
  // isStable approach is ready just within 5 bars, not in 10
  var sma = new SMAIndicator(new SMAIndicator(closePriceIndicator, 5), 5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Issue describing or discussing an enhancement for this library
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants