rbed

Finance

Daily closing prices fall for 300 days and then rise. A golden cross is the 50-day simple moving average of the price crossing above the 200-day one, a death cross crossing below it.

The live chart and its controls need JavaScript. The tables show the Events at the default parameters.

The site cannot run the default parameters: (JavaScript) TypeError: Cannot read properties of undefined (reading 'length')

import io.github.romanhaendler.rbed.*;
import java.util.Map;

Channel price = Channel.named("price");

Rule deathCross = Rule.named("DeathCross").when(
    price.averageOverSamples(50).below(price.averageOverSamples(200)));
Rule goldenCross = Rule.named("GoldenCross").when(
    price.averageOverSamples(50).above(price.averageOverSamples(200)));
Detector detector = Detector.builder()
    .rules(deathCross, goldenCross)
    .build();

for (int day = 0; day < 600; day++) {   // daily closing prices: falling, then rising from day 300
  double close = day < 300 ? 200 - day / 3.0 : 100 + (day - 300) / 2.0;
  detector.push(day * 86_400_000L, Map.of(price, close));
}
detector.close();

The Rules

  • DeathCross: the fast average below the slow one.
  • GoldenCross: the fast average above the slow one.

averageOverSamples(n) is defined once n values exist, so the first Event starts once the longer of the two averages exists: on day 199 here, later with a longer one.

At the defaults, DeathCross runs from day 199 to day 366. It is Truncated at its start: when both averages first exist, on day 199, the 50-day one is already below, so nobody knows when it crossed. GoldenCross follows from day 366, the day the example also finds by brute force over the two averages. It still holds when the data ends on day 599, so its end is Truncated.

Things to try

  • Raise Slow average over to 300 Samples: the slow average first exists on day 299, so DeathCross starts there, Truncated, and GoldenCross follows on day 388.

Reference

The example is TradingSignalsExample, a test with its expected Events, listed in the README's Examples.

Methods used: Channel.named, Rule.named, Rule.when, ChannelExpression.averageOverSamples, Expression.below, Expression.above, Detector.builder, Detector.Builder.rules, Detector.Builder.build, Detector.push, Detector.close.

The concepts at work, each on a page of its own: Conditions and Expressions, The Event lifecycle.