Zum Inhalt springen

Node-Spezifikation

Bellchain hat genau eine Spezifikation für Bausteine (Nodes). Die 25 offiziellen Bausteine sind genauso gebaut, wie später Community-Bausteine gebaut werden. Wer verstanden hat, wie der RSI funktioniert, kann einen eigenen Baustein schreiben. Die Pakete heißen @bellchain-app/node-spec (Typen, defineNode(), Zeitreihen, Chain-Format) und @bellchain-app/nodes (die offiziellen Bausteine), beide unter MIT-Lizenz.

hull-ma.ts
import { defineNode, l, series } from '@bellchain-app/node-spec';
export default defineNode({
id: 'community.hull-ma',
version: '1.0.0',
category: 'ind',
label: l('Hull Moving Average', 'Hull Moving Average'),
description: l('Schneller Durchschnitt mit wenig Verzögerung', 'Fast average with little lag'),
inputs: [{ id: 'in', type: 'series', label: l('Wert', 'Value') }],
outputs: [{ id: 'out', type: 'series', label: l('HMA', 'HMA'), unit: 'input' }],
settings: {
length: { type: 'number', label: l('Perioden', 'Periods'), default: 21, min: 2, max: 500, integer: true },
},
// So erscheint der Baustein auf dem Board
sentence: ({ settings }) => `HMA ${settings.length}`,
// Kerzen, die vor dem ersten verlässlichen Wert nötig sind
warmup: ({ settings }) => settings.length + Math.floor(Math.sqrt(settings.length)),
// Rein: kein Netz, kein Speicher, keine Uhrzeit
compute({ inputs, settings }) {
return { out: series.hma(inputs.in, settings.length) };
},
// Pflicht: bekannte Werte, gegen die jede Version getestet wird
tests: [{ fixture: 'binance-btcusdt-1h-500', settings: { length: 21 }, expectLast: { out: 81372.42333679654 } }],
});

defineNode() prüft die Definition sofort und meldet alle Probleme auf einmal. TypeScript leitet aus Pins und Einstellungen die Typen von compute() ab: settings.length ist eine Zahl, inputs.in eine Zahlenreihe.

  • id mit Namensraum: core.rsi, community.hull-ma. core gehört den offiziellen Bausteinen.
  • version als semantische Version. Ändert sich das Rechenergebnis, steigt die Hauptversion; Chains können sie mit core.rsi@1 festhalten.
  • category: src Quellen, ind Indikatoren, cond Bedingungen, logic Logik & Timing, data Daten & Text, act Aktionen, tool Werkzeuge.

Jeden sichtbaren Text gibt es auf Deutsch und Englisch, gebaut mit l('Kurs', 'Price'): Name, Beschreibung, Hilfe, jeder Pin, jede Einstellung, jede Auswahl. Fehlt eine Sprache, lehnt defineNode() die Definition ab.

Typ Inhalt Im Editor
series Zahlenreihe, ein Wert pro Kerze; null heißt „noch kein Wert“ wie na in Pine rund
signal wahr oder falsch pro Kerze eckig
text Nachricht mit Platzhaltern, nur von der Nachrichtenvorlage zur Aktion Raute

Eingänge können optional: true sein oder mitwachsen: variadic: { min, max } ergibt die Pins in0, in1 … Ausgänge können eine Einheit tragen: price erscheint als Kurs, percent mit Prozentzeichen, input wie der Eingang.

Art Felder
number default, min, max, step, integer, unit
select default, options: [{ value, label }]
text default, minLength, maxLength, pattern, format (timezone oder url), required, multiline, placeholder

Alle haben label, optional help und advanced: true (erscheint unter „Mehr“). Der Standardwert muss die eigenen Grenzen einhalten.

compute() bekommt ganze Reihen und liefert ganze Reihen, eine pro Ausgang. Für jeden rechnenden Baustein gilt:

  1. Rein und deterministisch. Kein Netz, kein Speicher, keine Uhrzeit, kein Zufall. Nur so kann Bellchain Ergebnisse über Chains hinweg teilen; RSI 14 auf BTC/USDT 1h rechnet die Engine einmal für alle.
  2. Kein Blick in die Zukunft. Der Wert an Kerze i hängt nur von Kerzen bis i ab. Was an einer Kerze steht, ändert sich nie mehr (kein Repainting).
  3. Eingänge nicht verändern.
  4. Jede Ausgangsreihe hat genau so viele Werte wie Kerzen.

Die Zeitreihen-Funktionen in series folgen Pine: sma, ema, rma, wma, hma, rsi, macd, stdev, bb, highest, lowest, roc, change, crossover, crossunder, cross.

  • state statt compute() für Bausteine mit Gedächtnis, etwa den Cooldown: init() und step() rechnen Kerze für Kerze, der Zustand ist JSON. Deshalb stimmen Replay und Livebetrieb überein.
  • source für Quellen: { kind: 'candles', market(settings) } deklariert Börse, Paar und Zeiteinheit; geladen wird von der Engine, nie vom Baustein.
  • effect für Aktionen: { kind: 'notify', channel: 'telegram' } oder { kind: 'log' }. Aktionen rechnen nicht; die Engine löst bei steigender Flanke aus und beachtet den Cooldown.

Nachrichten werden erst beim Auslösen ausgefüllt, in Sprache und Zeitzone des Empfängers:

Platzhalter Englisch Inhalt
{{kette}} {{chain}} Name der Chain
{{werte}} {{values}} Werte der beteiligten Bausteine, etwa „RSI 14: 27,69 · Kurs: 77.788 $“
{{kurs}} {{price}} Schlusskurs der Kerze
{{paar}} {{pair}} Handelspaar, etwa BTC/USDT
{{coin}} Basiswährung, etwa BTC
{{zeit}} {{time}} Kerzenschluss
{{a}} bis {{d}} Werte an den Eingängen A bis D der Nachrichtenvorlage

Unbekannte Platzhalter bleiben stehen, damit Tippfehler auffallen.

Jeder Baustein mit Kursbezug bringt Tests im Manifest mit: feste Kursdaten rein, bekannte Werte raus. Die Referenzwerte der offiziellen Bausteine stammen aus einer unabhängigen Nachrechnung, nicht aus dem Code, den sie prüfen. Das Testkit prüft zusätzlich Determinismus und Kausalität.