Java Ermitteln, ob der RSI-Wert von unten nach oben verläuft

Status
Für weitere Antworten geschlossen.

kali-hi

Lieutenant
Registriert
Sep. 2025
Beiträge
685
Diese Methode ist recht wichtig, deshalb wollte ich wissen, ob meine Implementierung richtig ist, und auch, wie dafür ein funktionaler Ansatz aussehen könnte.

Es soll geprüft werden, ob der RSI-Wert von unten nach oben kreuzt und aktuell über einem festen Wert liegt. Dafür muss ich doch nur über eine bestimmte Zeitspanne die lokalen Minima und Maxima ermitteln - oder? Wie lang muss diese Zeitspanne denn sein?

Könnte diese Methode auch anders implementiert werden? Und ist der Doc-String auch richtig, oder ist er "zu blumig" (also zu sehr "Wie?", anstatt "Was?" betont) geschrieben?

Java:
  /**
   * Checks whether the RSI has risen from below 50 to above 50 in recent periods.
   *
   * <p>To do this, local minima and maxima of the RSI values in the last look-back periods are
   * determined and compared to determine whether the minimum occurred before the maximum. Finally,
   * this method checks whether the last RSI value is above 50.
   *
   * @return true if RSI has risen from below 50 to above 50, false otherwise
   */
  public boolean isRsiRisesFromBelowToAbove50() {
    final int lookBackPeriods = 6;
    ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
    RSIIndicator rsiIndicator = new RSIIndicator(closePrice, RSI_PERIOD);
    final int endIndex = series.getEndIndex();
    int minIndex = endIndex - lookBackPeriods;
    int maxIndex = endIndex - lookBackPeriods;
    for (int i = endIndex - lookBackPeriods + 1; i < endIndex; i++) {
      double rsiValue = rsiIndicator.getValue(i).doubleValue();
      if (rsiValue < rsiIndicator.getValue(minIndex).doubleValue()) {
        minIndex = i;
      }
      if (rsiValue > rsiIndicator.getValue(maxIndex).doubleValue()) {
        maxIndex = i;
      }
    }
    double lastRsi = rsiIndicator.getValue(endIndex).doubleValue();
    return minIndex < maxIndex && lastRsi > 50.0;
  }
 
Wie sehen deine Unit-Tests dazu aus?

Weil wenn etwas wichtig ist und auch wenn etwas unwichtig ist, dann schreibt man Tests, um die Funktionalität sicherzustellen. Und wenn etwas wichtig ist, dann entsprechend viele und durchdachte Tests.

Edit: Im Übrigen kann ich nicht nachvollziehen, dass die Methode das macht, was die JavaDoc aussagt: "Checks whether the RSI has risen from below 50 to above 50 in recent periods". Aber ich wiederhole mich: Mit Unit-Tests könnte man das leicht zeigen/widerlegen.

Wichtig: Unit-Tests nicht nur mit "Confirmation Bias" schreiben, sondern eben auch Negativ-Beispiele usw, die Logik an "die Grenzen" bringen.
Doof gesagt: Bei einer Prüfung, ob ein Datum vor einem anderen liegt, nicht nur prüfen, dass es davor liegt, sondern auch prüfen, dass wenn ein dahinterliegendes Datum kommt, es auch auch erkannt wird.

Und: Bei so einem wichtigen Code könnte man durchaus sich vorher überlegen, welche Szenarien man testen möchte. Und dann schaut man, ob der Code diese erfüllt. Sich zu überlegen, welche Werte zu welchem Ergebnis führen, das kann vollständig unabhängig von der Implementierung geschehen, muss nicht mal von einem Entwickler kommen sondern kann idealerweise auch von jemand kommen, der sich fachlich damit auskennt.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: BeBur, madmax2010, kali-hi und 2 andere
Und zur JavaDoc: Da kann man sich streiten, aus meiner Sicht ist es aber durchaus okay bis hin zu sinnvoll. Vor allem auch, wenn es eine "wichtige Funktion" ist. Der von mir angesprochene Teil, den sehe ich in der Implementierung nicht.
Den Algorithmus bzw. die Idee zu beschreiben, der implementiert wird, das kann schon sinnvoll sein, damit der Nutzer das Ergebnis verstehen kann.

Nehmen wir eine Methode, die prüft, ob ein Element in einer Menge enthalten ist. Performance-Fragen mal außen vor, spielt es für den Aufrufer keine Rolle, wie das Ding implementiert wurde, weil der Nutzer hier selbst ziemlich genau weiß, welche Eingaben zu welchem Ergebnis führen sollen, also seine Erwartungshaltung ist ziemlich eindeutig. Und so lange die Methode nicht falsch implementiert ist, wird diese auch erfüllt.
Wie genau diese Prüfung umgesetzt wird, das ist nicht unbedingt wichtig.

Hier also zu beschreiben, wie die Methode zu ihrem Ergebnis kommt, das kann also schon sinnvoll sein. Wobei gerade "recent" schwammig ist und nicht erklärt wird.

Edit:
Ach, und der Methodenname ist merkwürdig: "isRises"? Ja was denn nun? Wenn dann eher "isRsiRising..."
Ergänzung ()

Und generell: Was heißt von unten nach oben?
Wenn wir das haben:
40, 60, 70, 65, 60, 55
das Minimim ist vor dem Maximum, das Maximum ist über 50. Verläuft also nach oben?
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: madmax2010, kali-hi und Nebuk
  • Gefällt mir
Reaktionen: kali-hi und tollertyp
@simpsonsfan: Eben. Solche Gedanken sollte man sich machen. Hier ist das Maximum sowohl vor als auch hinter dem Minimum, auch wenn es bei double-Werten vermutlich unwahrscheinlicher sein dürfte, dass so etwas passiert, es ist möglich.

Das ist auch das, was ich meinte, dass man bzgl. Confirmation Bias aufpassen muss und halt nicht nur "Schön-Wetter-Testfälle" nimmt.
 
  • Gefällt mir
Reaktionen: simpsonsfan und BeBur
tollertyp schrieb:
Das ist auch das, was ich meinte, dass man bzgl. Confirmation Bias aufpassen muss und halt nicht nur "Schön-Wetter-Testfälle" nimmt.
Was macht dieses Ding eigentlich wenn in den Eingabedaten weniger als 6 Elemente drin sind?
 
  • Gefällt mir
Reaktionen: madmax2010
foofoobar schrieb:
wenn in den Eingabedaten weniger als 6 Elemente drin sind?
Moin, das ist ausgeschlossen, series enthält immer 500 Elemente. Aber man sollte es zusätzlich checken, ja

tollertyp schrieb:
auch wenn es bei double-Werten vermutlich unwahrscheinlicher sein dürfte, dass so etwas passiert,
Eben, der RSI ist quasi niemals eine ganze Zahl, sondern hat quasi immer ganz viele Nachkommastellen...

tollertyp schrieb:
Und generell: Was heißt von unten nach oben?
Wenn wir das haben:
40, 60, 70, 65, 60, 55
das Minimim ist vor dem Maximum, das Maximum ist über 50. Verläuft also nach oben?
Das ist mir selber nicht ganz klar. Ich denke, das liegt an der Anzahl von lookbackPeriods... Oder ist meine ganze Herangehensweise falsch? Ich wollte nicht nur die zwei letzten RSI-Werte vergleichen, sondern etwas zurück in die Vergangenheit gehen, um auch zu erkennen, ob der RSI wirklich "kreuzt" und nicht nur in "Schlangenlinie" um 50.0 herum verläuft
 
Es hängt halt davon ab, was gewünscht ist.
Deshalb vorher spezifizieren, welche Eingangswerte zu welchem Ergebnis führen sollen, und da halt diverse Fälle nehmen.
Und nicht implementieren und sich dann überlegen, ob es das ist, was man haben möchte.
 
kali-hi schrieb:
Ich wollte nicht nur die zwei letzten RSI-Werte vergleichen, sondern etwas zurück in die Vergangenheit gehen, um auch zu erkennen, ob der RSI wirklich "kreuzt" und nicht nur in "Schlangenlinie" um 50.0 herum verläuft
Wenn Werte schwanken können, dann sollte man wahrscheinlich Verfahren der Trendanalyse verwenden. Eine lineare Regression lässt sich z.B. recht einfach implementieren.
 
  • Gefällt mir
Reaktionen: kali-hi und tollertyp
@Nolag Danke, genau das hatte ich gesucht.

Link 1
Link 2

Lineares Trendmodell:

Java:
  /**
   * Checks whether the RSI has risen from below 50 to above 50 in the recent 10 periods.
   *
   * <p>To do this, we perform a linear regression on the RSI values over the last 10 periods, and
   * check if the fitted line crosses the 50 level.
   *
   * @return true if RSI has risen from below 50 to above 50, false otherwise
   */
  public boolean isRsiRisingFromBelowToAbove50() {
    final int lookBackPeriods = 10;
    ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
    RSIIndicator rsiIndicator = new RSIIndicator(closePrice, RSI_PERIOD);
    final int endIndex = series.getEndIndex();
    final int startIndex = endIndex - lookBackPeriods + 1;

    // Linear Regression:
    // Collect RSI values
    double[] rsiValues = new double[lookBackPeriods];
    for (int i = 0; i < lookBackPeriods; i++) {
      rsiValues[i] = rsiIndicator.getValue(startIndex + i).doubleValue();
    }
    // Calculate Sums
    double xSum = 0, ySum = 0, xxSum = 0, xySum = 0;
    for (int i = 0; i < lookBackPeriods; i++) {
      xSum += i;
      ySum += rsiValues[i];
      xxSum += i * i;
      xySum += i * rsiValues[i];
    }
    // Calculate slope and intercept
    double slope =
        (lookBackPeriods * xySum - xSum * ySum) / (lookBackPeriods * xxSum - xSum * xSum);
    double intercept = (ySum - slope * xSum) / lookBackPeriods;
    // Generate fitted values
    double[] fittedValues = new double[lookBackPeriods];
    for (int i = 0; i < lookBackPeriods; i++) {
      fittedValues[i] = slope * i + intercept;
    }

    // Log the fitted values for debugging
    logger.debug(
        "{} RSI Linear Regression fitted values: {}",
        NAME,
        java.util.Arrays.toString(fittedValues));

    // Check if fitted values cross 50
    double fittedMin = fittedValues[0];
    double fittedMax = fittedValues[fittedValues.length - 1];
    return fittedMin < 50.0 && fittedMax > 50.0;
  }

Das müsste es sein, wenn nicht noch ein Fehler dabei ist.
 
tollertyp schrieb:
Ich stelle einfach erneut die Frage: Wie sehen denn die Tests aus?
Danke für die Frage, hatte schon in seinem letzten Thema überlegt danach zu fragen.

Ich denke ich habe von diesem User, auch unter diesem Nickname, noch nie einen Test gesehen.

kali-hi schrieb:
Es gibt noch keine.
Ich habe schon des öfteren von dir zum Thema Clean Code gelesen, auch Akronyme die du dazu gerne raus haust. DRY, YAGI etc. Neulich schriebst du ja auch das Debugger obsolet seien, wenn man Clean Code anwendet/lebt. Diese Meinung hattest du da schon exklusiv.

Wenn es noch keine Tests gibt, wann gedenkst du denn welche zu schreiben? Gehört zu Clean Code nicht auch TDD? Tests am Anfang zu schreiben einfach um seine Spezifikationen darüber zu konkretisieren oder gar zu verfeinern? Bzw. sich beim formulieren von Tests erstmal bewusst zu machen, was man als konkretes Ergebnis haben will? Lucky Path, Sad Path, Edge Cases, all diese Tests von Beginn an, das führt doch erst zu robusten Code.
 
  • Gefällt mir
Reaktionen: tollertyp und kali-hi
Ich schreib später mal einen JUnit 5 Test... Nur muss ich dann auch den "Data Supplier", also die Datenquelle..., mocken, und dazu hatte ich noch keine Lust.


Bob.Sponge schrieb:
Es gibt in Softwareentwicklungsprojekten unterschiedliche Ansätze bzw. Paradigmen... TDD ist eins davon. Im agilen Rapid-Modell (RAD) ist es aber oft so, dass Tests erst nachträglich oder sogar gar nicht geschrieben werden, also so ganz abtrünnig ist mein Ansatz auch nicht
 
kali-hi schrieb:
Es gibt in Softwareentwicklungsprojekten unterschiedliche Ansätze bzw. Paradigmen... TDD ist eins davon. Im agilen Rapid-Modell (RAD) ist es aber oft so, dass Tests erst nachträglich oder sogar gar nicht geschrieben werden, also so ganz abtrünnig ist mein Ansatz auch nicht

Klar, es gibt verschiedene Ansätze und Paradigmen oder Denkschulen.

Wenn ich jetzt mal Clean Code (nach Uncle Bob) nehme, dann ist TDD da integraler Bewstandteil. Erst Testcode schreiben, dann Produktivcode. Von daher kann es natürlich sein, das wir beide Clean Code anders verstehen/interpretieren. YAGNI, KISS, DRY etc. scheinen dir ja ein gewisses Anliegen zu sein, TDD eben überhaupt nicht - wäre z.b für mich völlig undenkbar TDD da auszuklammern.
Soweit so gut, entscheidet ja jeder selber wie dogmatisch bzw. pragmatisch er Ansätze in seinen Alltag adaptiert.

Zu RAD finde ich nur das: RAD also den Ranz mit dem ich in den 90ern arbeiten musste, Visual Basic 6, Delphi und Konsorten. Da dachte noch keiner ans automatisierte testen^^ bzw. war in den IDE's gar nicht vorgesehen.

Zu agilem RAD, konnte ich nichts finden das mir Klarheit brachte. SCRUM, AGILE, KANBAN, JIRA und all die Buzzwords kenne ich mittlerweile auch eher von zertifizierten PowerPoint Experten, also BWLern.

Aber möglicherweise verstehe ich einfach nicht was agiles RAD ist und wie die beiden (für mich) eher konträren Begrifflichkeiten zusammenpassen.

Von daher wäre ich dankbar für einen Link zu dieser Vorgehensweise. Einfach um dieselbe "Sprache" zu sprechen.
 
  • Gefällt mir
Reaktionen: tollertyp
Man könnte natürlich auch eine Methode so schreiben, dass sie einfach eine Liste oder ein Array von Werten bekommt, dann müsste man gar nichts mocken. "final int lookBackPeriods = 10;" wäre dann implizit die Größe dieser Liste. Und die eigentlich Methode, die du jetzt hast, tut nichts anderes als die 10 Werte zu holen und sie an diese Methode zu delegieren.

Ich weiß, das wäre vermutlich zu sauber und zu leicht testbar und bräuchte kein Mocking, weil diese Methode gar nicht vom Zustand von irgendwas abhängen würde.

Und ich kann verstehen, dass TDD nicht immer einfach umzusetzen ist, bei meiner Arbeit ist es häufig so, dass ich erst während der Entwicklung eines Features genau sagen kann, wo das Feature im Code landen wird. Aber es hindert niemanden daran, sich vorher Gedanken zu machen, wie etwas getestet werden kann.

Mit Verlaub: Wie soll man wissen, ob etwas richtig umgesetzt ist, wenn man nicht mal weiß, welche Daten zu welchen Ergebnissen führen sollen? Und wenn der "Auftraggeber" das nicht kann, dann sage ich "dann kann ich es auch nicht umsetzen, wenn du mir nicht sagen kannst, wie es sich verhalten soll".

Ich stand mal vor der Aufgabe, aus 3 Personen anhand eines Regelwerks einen "gemeinsamen" Text zu bilden. Das Regelwerk war nicht ganz einfach. Am Ende habe ich eine Liste von allen Kombinationen gemacht, die es geben kann. Ich habe dann meine "Vermutung" schon dazu geschrieben und die verantwortlichen Fachkollegen gebeten zu prüfen, ob meine Interpretation der Regeln richtig war und falls nicht, die entsprechende Zeile zu korrigieren. Und das habe ich dann auch so als Grundlage für die Unit-Tests genommen. Es waren glaube ich dann so 30 Kombinationen und es gab nur 5 unterschiedliche Varianten, wie der Text gebildet wird, aber dennoch war es am Ende so leichter nachzuvollziehen.

Und erst als ich das hatte, habe ich dann auch mit der Implementierung begonnen, aber habe auch kein TDD gemacht.

Ich persönlich dachte, dass TDD zu Extreme Programming gehört und das Extreme Programming eigentlich zu Clean Code führt, aber TDD nicht Voraussetzung für Clean Code ist? Uncle Bob würde sowieso etwas sagen wie: Mach, wie du es willst, aber überlege dir gut, warum du es so machst.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Bob.Sponge
tollertyp schrieb:
Ich weiß, das wäre vermutlich zu sauber und zu leicht testbar und bräuchte kein Mocking, weil diese Methode gar nicht vom Zustand von irgendwas abhängen würde.
Also, Ironie und Sarkasmus bitte sparen...

Das könnte man machen (statische Hilfsmethode), aber andererseits werden die Daten in dem Objekt gespeichert - deshalb ist es ohne Parameter besser, auch wenn der Testaufwand höher ist.

Ich habe die abschließende Bedingung der Methode gerade noch einmal angepasst:

Java:
  /**
   * Checks whether the RSI has risen from below to above 50 using linear regression over recent
   * bars.
   *
   * @return true if RSI has risen from below to above 50, false otherwise
   */
  private boolean isRsiRisingFromBelowToAbove50() {
    ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
    RSIIndicator rsiIndicator = new RSIIndicator(closePrice, RSI_PERIOD);
    final int endIndex = series.getEndIndex();
    final int startIndex = endIndex - RSI_LOOK_BACK + 1;
    // Linear Regression:
    // Collect RSI values
    double[] rsiValues = new double[RSI_LOOK_BACK];
    for (int i = 0; i < RSI_LOOK_BACK; i++) {
      rsiValues[i] = rsiIndicator.getValue(startIndex + i).doubleValue();
    }
    // Calculate Sums
    double xSum = 0, ySum = 0, xxSum = 0, xySum = 0;
    for (int i = 0; i < RSI_LOOK_BACK; i++) {
      xSum += i;
      ySum += rsiValues[i];
      xxSum += i * i;
      xySum += i * rsiValues[i];
    }
    // Calculate slope and intercept
    double slope = (RSI_LOOK_BACK * xySum - xSum * ySum) / (RSI_LOOK_BACK * xxSum - xSum * xSum);
    double intercept = (ySum - slope * xSum) / RSI_LOOK_BACK;
    // Generate fitted values
    double[] fittedValues = new double[RSI_LOOK_BACK];
    for (int i = 0; i < RSI_LOOK_BACK; i++) {
      fittedValues[i] = slope * i + intercept;
    }
    // Check if fitted values cross 50
    double fittedMin = fittedValues[0];
    double fittedMax = fittedValues[fittedValues.length - 1];
    logger.info("{} RSI Linear Regression fitted min: {}, max: {}", NAME, fittedMin, fittedMax);
    return fittedMax > 50.0 && fittedMin < fittedMax;
  }

Der RSI muss jetzt nur noch über 50.0 liegen und steigend sein. Außerdem genügen 5 Werte zurück.

Es hatte sich nämlich gezeigt, dass die vorherige Regel "zu streng" war... also sprich, es gab kein Kaufsignal mehr.
 
tollertyp schrieb:
Ich persönlich dachte, dass TDD zu Extreme Programming gehört und das Extreme Programming eigentlich zu Clean Code führt, aber TDD nicht Voraussetzung für Clean Code ist? Uncle Bob würde sowieso etwas sagen wie: Mach, wie du es willst, aber überlege dir gut, warum du es so machst.
Nee, genauso habe ich das auch in Erinnerung: Mit XP, wohl dem Beginn des agilen Ansatzes der Softwareentwicklung, hat TDD Einzug in die Diskussion unter den "Cracks" gehalten und damit sich dort auch etabliert. Ein ganz früher Advocate von XP war dann auch Uncle Bob der Schulungen und Mentoring zum Thema professionell angeboten hat. Anfang der 90er müsste das gewesen sein.
Mehr als 10 Jahre später hat er dann ja auch "Clean Code" veröffentlicht. Also da ist noch einiges mehr in ihm weiter gereift. Ich glaube Kapitel 9 in Clean Code befasst sich mit den 3 golden Regeln des TDD.
Klar, es ist dogmatisch formuliert.. aber wie du schon sagst überlässt er die Gewichtung bzw. Einhaltung all seiner Gedanken oder Ratschläge dem enzelnen Entwickler, solange dieser weiß was er tut und das er gute Gründe hat es so und nicht anders zu tun, wie er es halt tut.

Ich werde nie die Kompetenz erlangen argumentativ solchen Leuten wie Uncle Bob oder Kent Beck zu widersprechen, drum bin ich eher einfach dankbar aus deren Erfahrungen und den daraus formulierten Leitsätzen partizipieren zu können.

Und ja, ein TDD Guru? Ich? Nein, ganz weit davon entfernt. TDD zu leben, zum täglichen Handeln zu machen. Das muss man lange üben, was alles andere als einfach ist, so einleuchtend die Theorie dahinter mir auch scheint.

Aber genug nun von mir zum Thema.. habe hier schon viel zu viel Platz gekapert.. sorry an Alle übrigens dafür. 😗

Edit: (01:08) - Einige für mich typische Rechtschreibfehler korrigiert
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: tollertyp und kali-hi
kali-hi schrieb:
Es gibt in Softwareentwicklungsprojekten unterschiedliche Ansätze bzw. Paradigmen... TDD ist eins davon. Im agilen Rapid-Modell (RAD) ist es aber oft so, dass Tests erst nachträglich oder sogar gar nicht geschrieben werden, also so ganz abtrünnig ist mein Ansatz auch nicht
Und es gibt Software die funktioniert und es gibt Software die nicht funktioniert.
 
Bob.Sponge schrieb:
Aber möglicherweise verstehe ich einfach nicht was agiles RAD ist und wie die beiden (für mich) eher konträren Begrifflichkeiten zusammenpassen.
Sorry, ich dachte erst, RAD sei ein agiles Entwicklungsmodell, ähnlich wie Scrum - aber eigentlich habe ich nur RAD mit Scrum verwechselt. In beiden Modellen schreibt man aber keine oder nur wenige Tests.

foofoobar schrieb:
Und es gibt Software die funktioniert ...
Was willst du andeuten? Meine funktioniert doch
 
Status
Für weitere Antworten geschlossen.

Ähnliche Themen

Zurück
Oben