What is a policy?

The Policy is responsible for creating the orders that will be placed at the broker. The most common use case is that a Policy does this based on the signals it receives from a Strategy (but there are other use cases).

A good Policy implementation is key in making your solution as robust as possible. Important things to consider when implementing a policy:

  • How to manage overall risk and exposure when market conditions change

  • What is a good allocation strategy, so how much of your buying power do you allocate to a certain asset

  • What order types to create

  • How to handle new orders when there are still open orders (for the same asset)

  • How to limit the maximum number of orders sent to a broker (circuit breaker)

  • How to deal with conflicting signals from strategies

  • How to handle yo-yo signals (buy-sell-buy-sell) that occur in a short timeframe

  • How to ensure there is still enough buying power left to avoid margin calls

If there is one thing that prevents algo-traders from going live, it is that there is not a robust policy in place that handles all the possible edge-cases. The logic required for a robust policy is anything but trivial and should always incorporate extensive testing.

Out-of-the-box policies


This is the default policy that will be used if no other policy is specified when creating an instance of the Roboquant class. It provides many constructor parameters that influence its behavior.

val policy = FlexPolicy(
    orderPercentage = 0.01,
    shorting = true,
    priceType = "OPEN",
    fractions = 4,
    oneOrderOnly = true,
    safetyMargin = 0.1,
    minPrice = 1000.USD

You can also extend the FlexPolicy and overwrite some of its methods. For example, to create different order types you would implement something like this:

class MyFlexPolicy : FlexPolicy() {

    override fun createOrder(signal: Signal, size: Size, price: Double): Order? {
        // We don't short in this example and exit orders are already covered by the bracket order
        if (size < 0) return null

        val asset = signal.asset

        // Create a bracket order with an additional take-profit and stop-loss defined
        return BracketOrder(
            LimitOrder(asset, size, price), // limit order at current price for entry
            TrailOrder(asset, -size, 0.05), // 5% trail order for take profit
            StopOrder(asset, -size, price * 0.98) // stop loss order 2% under current price


There are several extension methods available that can add functionality to any type of policy by creating a chain of policies in which each policy has a particular tasks. Typically, the extension methods perform one of two tasks:

  1. Remove signals before the next policy is invoked

  2. Remove orders before they are handed to the broker

val policy = MyPolicy()
    .resolve(SignalResolution.NO_CONFLICTS) // remove all conflicting signals
    .circuitBreaker(10, 1.days) // stop orders if there are too many created

Fractional Order sizes

Roboquant doesn’t make assumptions on the minimal order and position sizes. They are not limited to integers only, and so there is no restriction on using a broker that supports fractional trading.

Since it is a Policy instance that creates the orders, here you can also put any type of order size logic you require.

The FlexPolicy allows you to specify the number of decimals for sizing calculations, allowing to easily enable fractional orders.

Custom Policies

In case the out-of-the-box policies will not do, you can implement your own Policy. You only have to implement a single method named act. This method has access to the generated signals and the Account and Event object.

class MyPolicy : Policy {

    override fun act(signals: List<Signal>, account: Account, event: Event): List<Order> {
        val orders = mutableListOf<Order>()
        // Your code goes here
        return orders

So a very naive and not robust implementation could look something like this:

class MyNaivePolicy : Policy {

    override fun act(signals: List<Signal>, account: Account, event: Event): List<Order> {
        val orders = mutableListOf<Order>()
        for (signal in signals) {
            val size = if (signal.rating.isPositive) 100 else -100
            val order = MarketOrder(signal.asset, size)
        return orders

Or using the more concise Kotlin way of doing things:

class MyNaivePolicy : Policy {

    override fun act(signals: List<Signal>, account: Account, event: Event): List<Order> {
        return signals.map {
            val size = if (it.rating.isPositive) 100 else -100
            MarketOrder(it.asset, size)

The following example is more realistic and shows an implementation that calculates the ATR (Average True Range). The ATR is then used to set the limit amount in a Limit Order.

This example uses the FlexPolicy as its base class that will take care of much of the logic like sizing and dealing with concurrent orders.

 * Custom Policy that extends the FlexPolicy and uses the ATR (Average True Range)
 * to set the limit amount of a LimitOrder.
class SmartLimitPolicy(val atrPercentage: Double = 0.02, val windowSize: Int = 5) : FlexPolicy() {

    // Keep track of historic prices per asset
    private var prices = PriceBarSeries(windowSize + 1)

    // Use TaLib for calculation of the ATR
    private val taLib = TaLib()

    override fun act(signals: List<Signal>, account: Account, event: Event): List<Order> {
        // Update prices, so we have them available when the createOrder is invoked.

        // Call the regular signal processing
        return super.act(signals, account, event)

     * Override the default behavior of creating a simple MarkerOrder. Create limit BUY and
     * SELL orders with the actual limit based on the ATR of the underlying asset.
    override fun createOrder(signal: Signal, size: Size, price: Double): Order? {
        val asset = signal.asset

        // We set a limit based on the ATR. The higher the ATR, the more the limit price
        // will be distanced from the current price.
        val priceBarSerie = prices.getValue(asset)
        if (! priceBarSerie.isFull()) return null

        val atr = taLib.atr(priceBarSerie, windowSize)
        val limit = price - size.sign * atr * atrPercentage

        return LimitOrder(asset, size, limit)

    override fun reset() {

When developing custom policies, they should not only be robust and deal with corner-cases, but they should also be explainable. Back-testing over large amounts of data is already challenging enough without having a Policy in place whose behavior is very difficult to wrap your head around. So the KISS design principle (Keep It Simple, Stupid) applies to policies.

When creating an order in a Policy, always validate if you still have an open order for the same asset and take the appropriate action.

Advanced Policies

Most commonly, a Policy is used to transform signals it receives from the Strategy into orders. But there are cases where the policy is not using Signals to create orders. Common use cases are:

  1. Re-balancing your portfolio at regular intervals (like monthly) based on some criteria. Since a Strategy doesn’t have access to an Account and therefore also not to the positions in the Account, this needs to be done in a Policy.

  2. Advanced machine learning techniques like reinforcement learning that train the algorithm to directly create orders based on events (without creating intermediate signals).

In these cases you don’t require a Strategy and you can implement all the logic in the Policy instead. You can use the NoSignalStrategy as strategy that doesn’t perform any action.

The following example shows the boilerplate code for a policy that at a regular interval (20 days) re-balances the portfolio:

class MyPolicy: Policy {

    private var rebalanceDate = Instant.MIN
    private val holdingPeriod = 20.days

     * Based on some logic determine the target portfolio
    fun getTargetPortfolio() : List<Position> {
        TODO("your logic goes here")

    override fun act(signals: List<Signal>, account: Account, event: Event): List<Order> {
        if (event.time < rebalanceDate) return emptyList()

        rebalanceDate = event.time + holdingPeriod
        val targetPortfolio = getTargetPortfolio()

        // Get the difference of target portfolio and the current portfolio
        val diff = account.positions.diff(targetPortfolio)

        // Transform the difference into MarketOrders
        return diff.map { MarketOrder(it.key, it.value) }

    override fun reset() { rebalanceDate = Instant.MIN }

val roboquant = Roboquant(
    NoSignalStrategy(), // will always return an empty list of signals
    policy = MyPolicy()