Roboquant

Create

The Roboquant class (org.roboquant.Roboquant) is the engine of the platform, not to be confused with roboquant (all small letters) which is the name of the platform itself. An instance of the Roboquant class orchestrates the interaction between all the components and performs the actual runs.

You are only required to provide a strategy when creating a new instance of Roboquant. So the bare minimum to get a working instance would look something like this:

val strategy  = EMACrossover()
val roboquant = Roboquant(strategy)

The following default values will then be used:

  • No metrics will be captured at all

  • The SimBroker will be used as the broker with its default settings

  • The DefaultPolicy will be the policy used

  • The MemoryLogger for logging the metrics (although without any metrics to capture, there is not much to log)

Each of these defaults can be overwritten with a different implementation when you instantiate a Roboquant, as the following code snippet demonstrates:

val roboquant = Roboquant(
    strategy,
    metric1, metric2, metric3,
    policy = myPolicy,
    broker = myBroker,
    logger = myLogger)

Run

After you have created an instance of the Roboquant class and have a data feed, you can start the run.

The same run method is used for all the different stages, from back testing to live trading. See also the 4 stages for more details about these stages.

In the most simple form, you only need to provide a feed as the argument. In this case, all the events available in the feed will be used in the run.

roboquant.run(feed)

If you provide a live feed, it would potentially run forever. However, you can restrict the run to a certain timeframe, again you can use this for a historical feed and a live feed alike.

// Historical feed run example
val timeframe = Timeframe.fromYears(2015, 2020)
roboquant.run(feed1, timeframe)

// Live feed run example
val timeframe2 = Timeframe.next(120.minutes)
roboquant.run(feed2, timeframe2)

You can invoke a run multiple times, for example with different timeframes. The following code shows how to use this to perform a walk-forward back test of two-year periods:

val timeframe = feed.timeframe
timeframe.split(2.years).forEach {
    roboquant.run(feed, it)
    println(roboquant.broker.account.equityAmount)
}

Running in Parallel

If you want to run many back-test, you can run them in parallel and leverage all the cores on your computer to expedite the process. Roboquant scales almost linear with the number of available cores, and it only requires a few extra lines of code.

The following example shows how to run a walk forward in parallel. By reusing the same logger instance, all results will be stored in a single instance and can be easily compared afterwards.

val timeframe = feed.timeframe
val logger = MemoryLogger(showProgress = false)
val jobs = ParallelJobs()

for (period in timeframe.split(2.years)) {
    jobs.add {
        // Create a new roboquant instance for each job
        val roboquant = Roboquant(EMACrossover(), AccountSummary(), logger = logger)

        // Give the run a unique identifiable name
        // Otherwise a unique name will be generated for each name
        roboquant.run(feed, period, runName = "run-$period")
    }
}

// Wait until all the jobs are finished
jobs.joinAllBlocking()

// If you are in Jupyter Notebook you can easily plot a metric for all the runs
val equity = logger.getMetric("account.equity")
MetricChart(equity)