Dokumentation1.0 (latest)
SeitenOHLCV- und Balkendaten · 10 / 29

OHLCV- und Balkendaten

QuantCraft-Backtests brauchen OHLCV-Kerzen (Eröffnung, Hoch, Tief, Schluss, Volumen) für jedes Symbol, das Sie handeln. Die Engine lädt diese Daten, bevor Ihre Strategie läuft, und steuert dann die Callbacks Ihres Strategie-Lebenszyklus in jedem Schritt mit einer Ansicht des aktuellen Balkens (bar). Am Ende des Laufs können Sie optional mit der vollständigen Serie arbeiten, die an on_finish(bars, …) übergeben wird. Konfigurieren Sie das Laden über Test (Code ausführen).

Diese Seite behandelt, woher die Daten kommen (Loader), wie Zeiträume und Warmup funktionieren und wie Sie das Vollserien-Argument bars in on_finish nutzen. Kombinieren Sie sie mit Fundamentaldaten, wenn Sie Kurs- und Einreichungsdaten mischen; siehe Kontomodell, wie Trades mit Kursen zusammenhängen.


Loader (Datenquellen)

Im Tab Symbol & data von Run backtest wählen Sie einen Kurs-Feed. Die Engine nutzt im Hintergrund einen von zwei Loadern:

Feed des verbundenen Brokers

  • Lädt Kerzen von Ihrem verbundenen Broker-Konto mit Ihrem API-Schlüssel und Secret oder einer per OAuth verknüpften Verbindung mit gültiger Link-ID.
  • Unterstützt US-Aktien und Krypto (die Anlageart wählen Sie im Dialog).
  • Unterstützt viele Zeitrahmen — täglich, wöchentlich, stündlich, 4-Stunden und mehrere Intraday-Minutenbalken (abgestimmt auf die Zeitrahmenbezeichnungen der Charts der App).
  • Die Historie wird in Blöcken abgerufen, bis der angeforderte Zeitraum erfüllt ist (oder bis eine Mindestbalkenzahl erreicht ist, wenn Sie den älteren Modus „ohne explizite Daten“ nutzen).

Nutzen Sie den Feed des verbundenen Brokers, wenn Sie Broker-gebundene Daten oder den vollständigen Satz an Intraday-Zeitrahmen (1 Minute bis 4 Stunden, dazu täglich und wöchentlich) wollen.

QuantCraft-Speicher (gehostet)

  • Lädt Kerzen aus dem gehosteten Speicher von QuantCraft, wenn Sie angemeldet sind (die App sendet Ihr Sitzungstoken).
  • Dateien sind nach Symbol und Zeitrahmen organisiert. Im kostenlosen Tarif bietet der Backtest-Dialog täglich, wöchentlich und monatlich; Premium schaltet Intraday und erweiterte Zeitrahmen frei.
  • Die vollständige Datei wird abgerufen und optional auf Ihren gewählten Kalenderzeitraum gefiltert.
  • Tagesbalken tragen ein reines Datum als t, etwa "2024-01-02", gelesen als UTC.

QuantCraft-B2-Zeitrahmencodes: 1s, 1m, 2m, m5, 15m, 30m, h1, 2h, 4h, d, w, m, q, y. Achtung: m bedeutet monatlich, nicht Minuten — 1 Minute ist 1m, 5 Minuten ist m5.

Hat ein Zeitraum keine Balken, schlägt das Laden mit einer Meldung fehl wie No AAPL bars (d) between 2010-01-01 and 2010-02-01. Available range is … to … — adjust the backtest dates.

Nutzen Sie den QuantCraft-Speicher, wenn Sie angemeldet sind, aber keine Broker-Zugangsdaten haben, oder wenn Sie gehostete OHLCV-Pakete aus dem QuantCraft-Symbolkatalog wollen (5 Minuten, stündlich, täglich, wöchentlich oder monatlich).

Auswahl zwischen beiden

BedarfTypische Wahl
Vollständiger Intraday-Satz des verbundenen Brokers (1m, 5m, 15m, 30m, 1H, 4H, …)Feed des verbundenen Brokers
5 Minuten oder stündlich aus dem QuantCraft-KatalogQuantCraft-Speicher
Täglich / wöchentlich / monatlich aus gehosteten DateienQuantCraft-Speicher
Verbundenes Broker-Konto + SchlüsselFeed des verbundenen Brokers
Angemeldeter Zugang ohne Broker-ZugangsdatenQuantCraft-Speicher

Lesen Sie in Strategie-Callbacks die Kurse aus dem bar-Objekt, das die Engine übergibt — nicht aus einem globalen OHLCV-Singleton. In der IDE ist das qc_ohlcv auf Modulebene beim Laden Ihrer Datei oft nicht gesetzt; sich darauf zu verlassen kann Ihren Code brechen. Es ist außerdem None in einem Lauf mit Screener-Ziel, und wo es gesetzt ist, umfasst es den gesamten geladenen Bereich einschließlich Warmup — nicht das ausgeführte Fenster, das der Chart zeichnet — und ist daher die falsche Quelle für Chart-Serien. Die bar-Ansicht ist für den aktuellen Simulationsschritt immer korrekt.


Zeiträume

Sie steuern, welche Balken am Backtest teilnehmen, mit Startdatum, Enddatum und optional Warmup.

Kalenderzeitraum (start_date + end_date)

Wenn Sie im Tab Simulation beide Daten setzen (Format YYYY-MM-DD, interpretiert als UTC-Kalendertage):

  • Die Engine behält nur Balken, die in dieses Fenster fallen.
  • Der Zeitraum wird als halboffenes Intervall behandelt: vom Beginn des Starttages bis zum Ende des Endtages nach der üblichen Konvention des Produkts (Balken des Kalendertags am Ende sind laut Engine-Konfiguration eingeschlossen).

Feed des verbundenen Brokers: Kerzen werden für diese Kalenderspanne angefordert.

QuantCraft-Speicher: Die vollständige Serie der Datei wird heruntergeladen und dann auf dasselbe Kalendertagsfenster gefiltert.

Wenn Sie beide Daten weglassen:

  • Der Feed des verbundenen Brokers nutzt einen älteren Rückwärtslauf: Die Engine geht in der Zeit zurück, bis genug Historie geladen ist (vorbehaltlich der Zeitrahmen-Grenzen), statt ein von Ihnen eingegebenes Kalenderfenster zu verwenden.
  • Der QuantCraft-Speicher nutzt alle Balken der Datei (kein zusätzlicher Filter).

Warmup-Balken (warmup_bars)

Optionale nicht negative Ganzzahl: zusätzliche Balken, die vor Ihrem Startdatum geladen werden, damit Indikatoren zurückblicken können, ohne dass ihnen die Historie ausgeht.

  • Warmup-Balken sind am ersten Ausführungsbalken über bar.close[1], bar.close[2], … und bar.bars_back sichtbar.
  • on_bar / on_tick / on_timer laufen weiterhin nur innerhalb Ihres gewählten Ausführungsfensters — Warmup dient nur der Historie, nicht zusätzlichen simulierten „Handelstagen“ im Ergebnis.

bar_index vs. Kalender

  • bar_index zählt nur Ausführungsbalken (der erste Balken in Ihrem gewählten Bereich ist 0, dann 1, …). Er zählt keine reinen Warmup-Balken.
  • Balken werden im Ausführungsfenster vom ältesten zum neuesten simuliert.

Balkendaten in Callbacks (bar)

Bei jedem on_bar und on_tick (und on_timer bei Forward-Läufen, sofern konfiguriert) übergibt die Engine bar: eine OHLC-Balkenansicht (OhlcvBarView) für das Symbol, für das der Callback gilt. Sie verhält sich wie ein schreibgeschütztes Mapping, aber isinstance(bar, dict) ist falsch — nutzen Sie bar["close"] oder Attributzugriff, keine reinen Dict-APIs.

Im Backtest erhält on_tick synthetische Kurse aus dem OHLC jedes Balkens (vier Aufrufe pro Balken, keine echte Tick-Historie). Bei Forward-Läufen wird on_tick bei jeder Live-Notierung Ihres verbundenen Brokers ausgelöst, während das Argument price den letzten Mark verfolgt — siehe Strategie-Lebenszyklus.

Sie können sie wie ein schreibgeschütztes Mapping verwenden:

o = float(bar["open"]) h = float(bar["high"]) l = float(bar["low"]) c = float(bar["close"]) v = float(bar["volume"]) t = bar["t"] # ISO timestamp string (QuantCraft B2 daily bars: a date like "2024-01-02", UTC)

Sie können außerdem die Historie relativ zum aktuellen Balken mit Offset-Indizierung lesen (derselbe Balken, frühere Schlusskurse usw.):

current_close = bar.close[0] prev_close = bar.close[1]
  • bar.close[0] ist der Schlusskurs des aktuellen Balkenkontexts (dieselbe Idee wie float(bar["close"]) im Backtest-on_bar) — siehe Balkenindizes in on_bar vs. on_tick, welcher Balken das in welchem Callback ist.
  • Größere Indizes laufen rückwärts in der Zeit; bar.bars_back sagt Ihnen, wie weit Sie zurückschauen können.

Balkenindizes in on_bar vs. on_tick

Offsets wie bar.close[0], bar.close[1], … zählen immer rückwärts vom neuesten Balken, den der Callback sehen kann — aber welcher Balken „der neueste“ ist, hängt vom Callback ab:

Diagramm mit drei abgeschlossenen Kerzen und einer sich bildenden Kerze. In on_bar ist die gerade geschlossene Kerze Balken 0, ältere Kerzen sind Balken 1 und 2. In on_tick ist die sich bildende Kerze Balken 0, die gerade geschlossene Kerze Balken 1, ältere Kerzen sind Balken 2 und 3.

  • on_bar wird ausgelöst, wenn ein Balken schließt. Index [0] ist dieser gerade geschlossene Balken, [1] der Balken davor, [2] der davor, und so weiter. Jeder Index zeigt auf einen abgeschlossenen Balken.
  • on_tick wird ausgelöst, während ein Balken noch entsteht. Index [0] ist der entstehende Balken (seine Werte ändern sich mit jedem Tick), [1] ist der zuletzt geschlossene Balken, [2] der davor, und so weiter.

Dieselbe Kerze liegt also in on_tick einen Index höher als in on_bar:

KerzeIn on_barIn on_tick
Entstehend (noch nicht geschlossen)nicht sichtbar[0]
Gerade geschlossen[0][1]
Eine davor[1][2]
Zwei davor[2][3]
def on_bar(bar_index, bar, fundamentals=None, symbol=None): last_closed = bar.close[0] # the bar that just closed one_before = bar.close[1] def on_tick(bar_index, tick_in_bar, price, bar, fundamentals=None, symbol=None): forming = bar.close[0] # still forming — latest price so far last_closed = bar.close[1] # same candle on_bar saw as [0]

Dieselbe Verschiebung gilt für jede Serie der Ansicht (open, high, low, close, volume). Wenn Sie Logik von on_bar nach on_tick verschieben, addieren Sie 1 zu jedem Offset, um dieselben Kerzen weiterzulesen.

Backtest: on_tick spielt den aktuellen Balken als vier synthetische Ticks ab, daher ist [0] dort der simulierte Balken, gelesen aus seiner vollständigen Zeile (siehe Volumen bei [0] unten) — es ist keine teilweise aufgebaute Kerze wie bei einem Forward-Lauf.

Genauigkeit der Live-Daten (Forward-Läufe)

Der Live-Kursstrom Ihres Brokers ist eine Näherung, kein vollständiges Protokoll des Marktes:

  • Kostenlose Live-Daten-Tarife sehen typischerweise nur Trades einer einzigen Börse — einen kleinen Bruchteil des gesamten US-Handels —, daher zeigen live aufgebaute Kerzen deutlich weniger Volumen und können die wahren Hochs und Tiefs verpassen.
  • Kostenpflichtige Konsolidierte-Feed-Tarife sehen jede Börse, aber Trades können weiterhin verzögert in Schüben eintreffen, besonders rund um die Eröffnung bei sehr aktiven Aktien.

Die App ersetzt jede live aufgebaute Kerze kurz nach dem Schließen durch den finalisierten historischen Balken des Brokers. Bei kleinen Zeitrahmen wie 1 Minute bedeutet das:

IndexWas es istWofür verwenden
bar.close[0]Die entstehende Kerze, aus Live-Ticks aufgebautDie aktuelle Kursschätzung
bar.close[1]Der gerade geschlossene Balken — kann in den ersten ca. 10–30 Sekunden noch tick-basiert seinDirekt nach Öffnung eines neuen Balkens mit Vorsicht verwenden
bar.close[2]Ein vollständig finalisierter BalkenSignale, die einen bestätigten Schlusskurs brauchen

Für Signale, die von einem bestätigten Schlusskurs auf 1-Minuten-Balken abhängen, bevorzugen Sie bar.close[2].

Volumen bei [0]:

  • Forward-on_tick: volume[0] der entstehenden Kerze ist vorläufig (oft die Größe eines einzelnen Ticks). Nutzen Sie volume[1] für das Volumen des zuletzt abgeschlossenen Balkens.
  • Backtest: Alle vier synthetischen Ticks verwenden die vollständige Balkenzeile — volume[0] ist das volle Balkenvolumen, keine vorläufige Tickgröße.

Dies ist der richtige Ort für Handelslogik pro Schritt: Einstiege, Ausstiege zum Balkenschluss, einfache gleitende Durchschnitte und alles, was nur den aktuellen Balken plus Rückblick braucht.


Primäre und zusätzliche Zeitrahmen (get_bar)

Der primäre Zeitrahmen des Laufs ist immer über rt.get_bar verfügbar (Sie müssen ihn nicht unter Additional timeframes aufführen). Braucht Ihre Strategie außerdem Balken in einer anderen Auflösung (zum Beispiel tägliche Trendfilter bei einem 5-Minuten-Backtest), wählen Sie diese Extras im Dropdown Additional timeframes des Dialogs Run backtest unter Symbol & data aus und lesen sie dann aus jedem Callback:

from quantcraft import Timeframe import quantcraft.runtime as rt def on_bar(bar_index, bar, fundamentals=None, symbol=None): # Primary TF works without listing it under Additional timeframes # (use the Timeframe member that matches the modal primary, e.g. M5): prev_primary = rt.get_bar(Timeframe.M5, shift=1) daily = rt.get_bar(Timeframe.DAILY, shift=1) if daily and bar.close[0] > daily.close: ... # primary bar closed above yesterday's daily close

Konfigurieren Sie Additional timeframes unter Backtests; speichern Sie Auswahlen in Ausführungsvorlagen (.qcs) unter secondaryTimeframes.

Felder von BarSnapshot

get_bar gibt einen BarSnapshot (oder None) zurück mit: open, high, low, close, volume, t.

Semantik von shift

shift.close.high / .low / .open
0Aktueller Ausführungskurs — über alle Zeitrahmen identisch im selben Callback (Backtest; siehe Forward-Hinweis unten)Aus dem gespeicherten Balken dieses Zeitrahmens — nicht vereinheitlicht mit dem primären Zeitrahmen
>= 1Schlusskurs des abgeschlossenen Balkens in diesem ZeitrahmenVollständiges OHLC des abgeschlossenen Balkens — zu bevorzugen für Dochte der Vorkerze

Backtest: get_bar sieht nur Balken bis zum aktuellen Simulationsschritt — nie spätere — im primären und in jedem zusätzlichen Zeitrahmen. Bei shift=0 sind sekundäre high/low pro Zeitrahmen zeitlich an die Simulationsuhr angepasst. get_bar liest die Balken des Taktsymbols; nutzen Sie in einem Multi-Symbol-Lauf für die Historie die bar.close[i] jedes Tickers.

Forward-Lauf: Der primäre bar folgt dem Zeitrahmen der Chart-Symbolleiste. Sekundäre Puffer werden aktualisiert, wenn ein Balken im Strom dieses Zeitrahmens abgeschlossen wird — high/low bei shift=0 können hinterherhinken, bis dieser Bucket abgeschlossen ist; bevorzugen Sie shift=1 für verlässliches OHLC des Vorbalkens. Das .close bei shift=0 ist im Forward-Lauf der jeweils eigene letzte Schlusskurs jedes Puffers, nicht vereinheitlicht über Zeitrahmen. In on_tick kann volume[0] des primären Balkens vorläufig sein (noch im Entstehen).

Gibt None zurück, wenn dieser Zeitrahmen für den Lauf keinen Puffer hat (nicht der primäre und nicht unter Additional timeframes gewählt), bei einem Screener-Backtest (kein Taktsymbol — nutzen Sie für die Historie die bar.close[i]-Offsets des jeweiligen Tickers) oder wenn Daten nicht verfügbar sind. Eine Backtest-Ausnahme: shift=0 auf einem nicht gewählten Zeitrahmen gibt den aktuellen Snapshot des primären Zeitrahmens zurück statt None.

tf kann ein Timeframe-Member oder ein String wie "1D" / "5Min" sein.

Enum Timeframe

Import mit from quantcraft import Timeframe:

MemberString-WertBeschreibung
M1"1Min"1-Minuten-Balken
M5"5Min"5-Minuten-Balken
M15"15Min"15-Minuten-Balken
M30"30Min"30-Minuten-Balken
H1"1Hour"Stundenbalken
H4"4Hour"4-Stunden-Balken
DAILY"1D"Tagesbalken
WEEKLY"1Week"Wochenbalken

Einige QuantCraft-B2-Zeitrahmen (2 Minuten, 2 Stunden, 1 Sekunde, monatlich m, quartalsweise q, jährlich y) haben kein Timeframe-Member — übergeben Sie sie als Strings an get_bar.


Optionale Vollserie: on_finish(bars, …)

Wenn die Simulation endet, ruft die Engine on_finish einmal auf. Definiert Ihre Strategie die erweiterte Signatur, erhalten Sie Vollserien-OHLC-Zeilen für die Nachbearbeitung — Indikatoren über den ganzen Lauf, Serien exportieren, finale Marks für refresh_metrics usw.

def on_finish(bars, symbol=None, bars_by_symbol=None): ...

bars — Taktsymbol, ältester zuerst

  • bars ist eine list von Dictionaries für das Taktsymbol (das Skript-SYMBOL, wenn dieser Ticker geladen ist, sonst das erste geladene Symbol — der Dialog hat kein Bedienelement für ein Primärsymbol). Bei einem Screener-Lauf gibt es kein Taktsymbol: bars ist [] und symbol ist "", nutzen Sie also bars_by_symbol.
  • Die Reihenfolge ist chronologisch: ältester Balken zuerst, neuester zuletzt — die umgekehrte Konvention gegenüber dem QcOhlcv-Index [0] = neuester in Notebook-artigen APIs.
  • Jede Zeile enthält mindestens open, high, low, close, volume und t, wenn Zeitstempel vorhanden sind. Sind Fundamentaldaten aktiviert, können Zeilen außerdem einen fundamentals-Snapshot für diesen Balken enthalten.

Typische Verwendungen:

def on_finish(bars, symbol=None, bars_by_symbol=None): if not bars: return closes = [float(b["close"]) for b in bars] last = float(bars[-1]["close"]) sym = (symbol or "AAPL").strip().upper() metrics = account.refresh_metrics({sym: last}) chart_indicators.add(...)

Nutzen Sie bars[-1]["close"] (oder die Felder der letzten Zeile) als finalen Mark beim Aufruf von account.refresh_metrics({symbol: last_price}), damit offene Positionen am Ende des Laufs bewertet werden.

Für chart_indicators bevorzugen Sie Werte, die Sie pro Symbol angesammelt haben, während der Lauf die Balken durchlief, und nutzen on_finish nur zur Übergabe; berechnen Sie aus bars nur Indikatoren neu, die Sie nicht pro Balken mitgeführt haben — siehe Indikatorserien.

bars_by_symbol — Multi-Symbol-Läufe

Wenn Sie mehr als einen Ticker backtesten, bezieht sich bars weiterhin nur auf das Taktsymbol. Für die vollständige, ausgerichtete Serie jedes Symbols nutzen Sie bars_by_symbol:

  • Ein Mapping Ticker in Großbuchstaben → Liste derselben Form wie bars (chronologische Dicts pro Symbol).
  • Nutzen Sie es, wenn Sie am Ende Cross-Sectional- oder symbolweise vollständige Historien brauchen (Korrelation, relative Stärke, Indikatoren pro Symbol).

Wann Sie on_finish nicht brauchen

Braucht Ihre Strategie nur den aktuellen Balken und Rückblick-Offsets, können Sie nur on_bar / on_tick implementieren und auf aufwendige Vollserien-Arbeit verzichten. on_finish ist für die Logik optional — aber dort werden die chart_indicators-Serien übergeben, und dort erhält refresh_metrics den letzten Kurs. Beachten Sie, dass jedes return in on_finish stumm ist: Der Lauf gelingt trotzdem, er überspringt nur, was danach kam.


Wie das mit Test Results zusammenhängt

Das strukturierte Backtest-Ergebnis enthält eine Liste ohlcv.bars (oder Entsprechendes): eine Zeile pro simuliertem Ausführungsschritt, mit OHLC-Feldern und optionalen fundamentals-Snapshots — abgestimmt auf das, was Sie in den Callbacks gesehen haben. on_finish(bars, …) ist dieselbe chronologische Serie, die die Engine für „Gesamtlauf“-Rechnungen des Taktsymbols nutzt, sodass Ihr Code am Laufende dem entspricht, was in Ergebnissen und Charts erscheint.


Kurzreferenz

ThemaZusammenfassung für Benutzer
LoaderFeed des verbundenen Brokers (Schlüssel + breites Intraday) vs. QuantCraft-Speicher (angemeldet; täglich / wöchentlich / monatlich, mehr mit Premium).
DatenYYYY-MM-DD Start + Ende → kalendergefiltertes Fenster; beide weglassen → älterer Rückblick des Broker-Feeds oder vollständige Datei des QuantCraft-Speichers.
WarmupZusätzliche Historie vor dem Start für bar-Offsets; Callbacks nur im Ausführungsfenster.
Pro SchrittNutzen Sie bar / bar["close"] / bar.close[k] in on_bar / on_tick. [0] = zuletzt geschlossener Balken in on_bar, entstehender Balken in on_tick.
Primäre / zusätzliche TFsPrimär immer über rt.get_bar; Extras über Additional timeframes + rt.get_bar(Timeframe.X, shift).
VollserieNutzen Sie on_finish(bars, symbol=..., bars_by_symbol=...) — bars ältester zuerst für das Taktsymbol; bars_by_symbol für alle Symbole bei Multi-Symbol-Läufen.
Globale FaktorrenditenNicht auf QcOhlcv oder bar — nutzen Sie Fama-French-Faktoren (fama_french.qc). Monatliche rows sind ein YYYYMM-Dict; nutzen Sie latest_row, nicht rows[0].
OHLCV- und Balkendaten — Dokumentation (1.0 (latest)) | QuantCraft