Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Journal

A journal captures and/or logs information at each step of a run. It is optional and if you don’t provide one during a run, there is only the account to see what happened during the run.

A journal is one of the optional parameters of the run() function and if provided will be invoked at every step of the run. A journal should NOT modify any of the passed parameters.

API

The API of the Journal is a single track(...) method with all signals and orders generated during this step.

Below is a custom Journal that prints all the available info to the console at each step of the run.

from roboquant.journals import Journal
from roboquant.common import Event, Account, Signal, Order

class MyJournal(Journal):
  
    def track(self, event: Event, account: Account, signals: list[Signal], orders: list[Order]) -> None:
        print(f"event={event} account={account} singals={signals} orders={orders}")

Another example is journal that guards some condition and stops the run if the condition is met.

from roboquant import stop_run

class GuardJournal(Journal):
  
    def track(self, event: Event, account: Account, signals: list[Signal], orders: list[Order]) -> None:
        if account.cash[rq.USD] < 1_000:
            stop_run()

BasicJournal

The BasicJournal has low overhead and tracks a number of basic statistics.

MetricsJournal

MetricsJournal collects and records metrics throughout a run, making it easy to track performance indicators like P&L, Sharpe ratio, drawdown, and custom metrics.

import roboquant as rq

from roboquant.journals import MetricsJournal
from roboquant.util.metrics import PNLMetric, RunMetric

feed = rq.feeds.YahooFeed.us_stocks_10()
strategy = rq.strategies.EMACrossover(12, 25)

# Collect P&L, run metrics, and account-level metrics
journal = MetricsJournal(PNLMetric(), RunMetric())
account = rq.run(feed, strategy, journal=journal)

# Inspect recorded metrics as a time-series (DataFrame)
df = journal.get_metrics("pnl/equity")
print(df.tail())
                             pnl/equity
2026-08-07 04:00:00+00:00  3.838165e+06
2026-08-10 04:00:00+00:00  3.845438e+06
2026-08-11 04:00:00+00:00  3.867325e+06
2026-08-12 04:00:00+00:00  3.845384e+06
2026-08-13 04:00:00+00:00  3.831731e+06

You can also develop custom metrics by subclassing Metric and implement the calc() method.

from roboquant.common.metric import Metric

class PositionCount(Metric):
    """Counts the number of open positions at each step."""
     
    def calc(self, event, account, signals, orders) -> dict[str, float]:
        return {
            "positions": float(len(account.positions()))
        }

TensorBoardJournal

This journal is similar to the MetricsJournal, but rather than keeping the results in memory it will write them to a TensorBoard compatible file.

So already during a run, the metrics can be inspected using a TensorBoard viewer.

from tensorboard.summary import Writer
import roboquant as rq
from roboquant.journals import TensorboardJournal
from roboquant.util.metrics import PNLMetric, RunMetric

feed = rq.feeds.YahooFeed.us_stocks_10()

# Compare runs with different parameters for the EMACrossover strategy
hyper_params = [(5, 10), (12, 25), (25, 50)]

for p1, p2 in hyper_params:
    # Each run will be logged to a different directory
    log_dir = f"runs/ema_{p1}_{p2}"
    writer = Writer(log_dir)
    journal = TensorboardJournal(writer, PNLMetric(), RunMetric())

    strategy = rq.strategies.EMACrossover(p1, p2)
    account = rq.run(feed, strategy, journal=journal)
    writer.close()
Microsoft ships a free Tensorboard plugin for Visual Studio Code that makes it
possible to run the viewer from within the IDE.