Savings Plans: Recurring Investments using Workflows

Set up recurring investment schemes using workflows.

Introduction

Recurring investments are one of the pillars of investment success. In fact, it’s so popular that different regions have established totally different terms for the same thing: Dollar Cost Averaging (US) or Savings Plans (DE; Sparpläne) are popular names; however, they all share the same fundamental properties: For each of these, a fixed amount of money is invested in the same security periodically, e.g. every month.

At lemon.markets, we manage programmatic investment instructions like this using workflows. A workflow is a building block allowing automatic creation of our existing order types. As such, it complements the existing API as a pure add-on.

Create a Workflow

Let’s start by creating a workflow for the account cusa_12345 to invest 12.50 € every month into an ETF:

# curl -sS -H 'LMG-Data-Privacy-Access-Principal: backend-cusa_12345' \
    -H 'LMG-Data-Privacy-Access-Justification: app.create_workflow' \
    -H 'Authorization: Bearer <your-api-key>' \
    -H 'Content-Type: application/json; charset: utf-8' \
    'https://sandbox.api.lemon.markets/v1/accounts/cusa_12345/workflows?unified_orders=true' \
    --data-binary '
    {
      "action": {
        "type": "order.create_and_confirm",
        "order": {
          "amount": "12.5",
          "currency": "EUR",
          "fee": "0",
          "instrument": "LU0290358497",
          "side": "buy",
          "type": "batch"
        }
      },
      "trigger": {
        "cadence": "monthly",
        "type": "schedule"
      }
    }' | jq 

As a result, you’ll see a response like this:

{
  "id": "wf_c34bf754daa34de1ba7ee668a06788c9",
  "trigger": {
    "type": "schedule",
    "cadence": "monthly"
  },
  "action": {
    "type": "order.create_and_confirm",
    "order": {
      "side": "buy",
      "instrument": "LU0290358497",
      "amount": "12.50",
      "fee": "0.00",
      "currency": "EUR",
      "type": "batch"
    }
  },
  "regulatory_disclosures": {
    "kid": "https://kid.dev-sandbox.lemon.markets/2023-11-17/LU0290358497-ac81558ef3e50c8eb4a01f7a68800963.pdf",
    "estimated_price": "141.3010",
    "estimated_quantity": "0.08846",
    "estimated_amount": "12.50",
    "service_costs_total": "0.00",
    "service_costs_total_pct": "0.03",
    "entry_costs": "0.00",
    "entry_costs_pct": "0.00",
    "…": "…"
  },
  "sca": {
    "required": false,
    "challenge": "aREfflZxxtFqKlxqgSAAHA=="
  },
  "appropriateness_consent": {
    "required": false
  },
  "history": [
    {
      "status": "created",
      "timestamp": "2024-04-22T14:39:34.292276+00:00"
    }
  ]
}

Confirm a Workflow

The created workflow requires confirmation by the customer. You can confirm a workflow on the sandbox without strong customer authentication (SCA) like this:

# curl -sS -H 'LMG-Data-Privacy-Access-Principal: backend-erika.mustermann%40example.com' \
    -H 'LMG-Data-Privacy-Access-Justification: create_workflow' \
    -H 'Authorization: Bearer <your-api-key>' \
    -H 'Content-Type: application/json; charset: utf-8' \
    'https://sandbox.api.lemon.markets/v1/accounts/cusa_12345/workflows/wf_c34bf754daa34de1ba7ee668a06788c9' \
    --data-binary '{}'

The response will contain the updated workflow. Information relevant for confirmation will be omitted now (regulatory disclosures, strong customer authentication, and appropriateness consent requirement). Let’s focus on the history here to see the status being updated:

{
  "…": "…",
  "history": [
    {
      "status": "confirmed",
      "timestamp": "2024-04-22T14:46:07.907882+00:00"
    },
    {
      "status": "created",
      "timestamp": "2024-04-22T14:39:34.292276+00:00"
    }
  ]
}

Order Creation

On the next execution day, there will be two relevant points in time:

  1. Cut-Off Time: In the morning of the trading day, the lemon.markets platform will prepare all savings plans for execution by creating and confirming new orders. If confirmation fails (e.g. due to insufficient funds), orders will be rejected. You will see events of type order.created, order.confirmed, and either order.accepted or order.rejected for this.
    • NOTE: At this point in time, cancelling a workflow will not cancel the order that was created. Instead, both the workflow and the created order have to be canceled separately.
  2. Execution Time: Later in the day, the orders will be executed. At that point, cancellation is no longer possible.

As the workflow captures information like regulatory disclosures, strong customer authentication and appropriateness consent, this information will not be exposed on orders created by a workflow. Instead, the order will refer to the workflow using the workflow property:

{
  "id": "bord_abd426e1a0e5478e851fca7379ea7765",
  "workflow": "wf_c34bf754daa34de1ba7ee668a06788c9",
  "created_at": "2024-04-23T07:00:03.740574+00:00",
  "side": "buy",
  "instrument": "LU0290358497",
  "amount": "12.50",
  "quantity": null,
  "fee": "0.00",
  "currency": "EUR",
  "status": "accepted",
  "history": [
    {
      "status": "accepted",
      "timestamp": "2024-04-23T07:00:06.607181+00:00"
    },
    {
      "status": "created",
      "timestamp": "2024-04-23T07:00:03.740574+00:00"
    }
  ]
}

Sequence Diagram

Sequence Diagram for Workflow Create and Confirm

Current Restrictions

  • Execution is restricted to a monthly schedule. The sandbox also provides a daily schedule for testing.
  • Workflows are immutable. If the amount should be changed, cancel the old workflow and create a new one.
  • Workflows can only buy shares for now. Divestment plans are not supported yet.

If your use-case exceeds these capabilities, feel free to contact us. We love expanding our product with new partners.