Metrics & Loggers

Metrics allow you to monitor the progress of a run and get the necessary insights how a strategy is performing. Metrics are not limited to back testing and can also be used during live testing and paper trading and live trading.

By default, the configured metrics are invoked at each step in a run. A single metric can return multiple values, each value having it own a unique name. Metrics only calculate the values, the storing and/or logging of these values is done by a MetricsLogger.

Standard Metrics

There are several commonly used metrics included with roboquant that can be added to your Roboquant instance:

val metric1 = AccountSummary()
val metric2 = PortfolioExposure()
val metric3 = ProgressMetric()
val metric4 = VWAPMetric()
val metric5 = SharpRatio()
val metric6 = PNL()
val metric7 = AlphaBeta(sp500Asset, 250)

val roboquant = Roboquant(
    strategy, metric1, metric2, metric3, metric4, metric5, metric6, metric7
)
if a metric is very compute intensive, and you don’t require it at each step, you can wrap it in a MetricsScheduler and configure when it should be invoked.

Custom Metrics

You can also develop your own metrics. All you have to do is implement the calculate method from the Metric interface and return MetricResults, which is a typealias for Map<String,Number>. If you don’t have any results, return an emptyMap()

In the calculate function you have access to both the Account object and the Event. Metrics also implement the Lifecycle interface, so you can keep state in a metric if required and clean it when a lifecycle method is invoked.

class MyMetric : Metric {

    private val asset = Asset("AAPL")

    override fun calculate(account: Account, event: Event): MetricResults {
        val metric1 = account.buyingPower.value
        val metric2 = event.getPrice(asset) ?: Double.NaN
        return mapOf("buyingpower" to metric1, "appleprice" to metric2)
    }

}

Metrics Loggers

A metrics loggers receives the metric values at each step and then stores and/or logs these values. They all implement the MetricsLogger interface.

The following metric loggers are available out of the box:

  • MemoryLogger: this is the default logger used if no other logger is configured. It stores all the recorded values in memory and allows them to be queried afterwards. It also comes with an optional progress-bar that shows how much time is remaining during a run.

    This logger is especially useful if you are using a Jupyter Notebook and after a run want to directly plot some metrics.

    // You can always find out which metrics are available after a run
    val logger = roboquant.logger
    println(logger.metricNames)
    
    // And easily plot a metric in a notebook
    val equity = logger.getMetric("account.equity")
    MetricChart(equity)
  • SilentLogger: this logger just silently ignores all calculated metric values and is mostly useful for unit tests

  • InfoLogger: logs metrics using the built-in logger at INFO level.

  • ConsoleLogger: logs the metrics to the console using a simple println statement.

Custom Loggers

You can also implement your own metrics logger, for example if you want to store values into a database or have a custom file format that you want to use. The following example shows a minimal example:

class MyConsoleLogger : MetricsLogger {

    private val database = Database()

    override fun log(results: MetricResults, info: RunInfo) {
        for ((key, value) in results) database.store(key, value, info.time)
    }

}