MesoSim v3.0 - Motivation

It’s been almost four years since the first public version of MesoSim was released.
During this time, MesoSim has continued to evolve - we’ve added tools to analyze strategy performance (Tearsheets, Event Log Analytics via DataVoyager, Risk Graphs in PositionMonitor), extended the Strategy Definition with three new Conditional Adjustments, introduced Reg-T and Portfolio Margin, and expanded Data Coverage with more tradable instruments. Many other smaller improvements are listed in the release notes.

Throughout these ongoing developments, our goal has been to minimize disruption by maintaining backward compatibility. As active traders ourselves, we understand the frustration that comes from unstable results or lack of reproducibility. We’re proud to say we achieved that goal: even the earliest backtests still run today without manual intervention.

Over time, we’ve learned how users use (and mis-use) our tools and identified the main design pitfalls and usability footguns. Most of these have been resolved, but a few issues required deeper, behavioral changes that would alter how strategy plans are processed – and therefore how results are generated. We decided to group these design corrections into a single major release to minimize the migration burden for our users.

Some of these design improvements include:

  • Job Definition structure:
    Originally tailored for backtesting, but with MesoLive we now support live trading. Structural updates are required to better support both:

    • Dedicated Backtest section defining backtest parameters

    • A generic Settings section that applies to both Simulator and Live Trading

    • Support for Leg Groups to manage live, complex orders

  • Strategy Definition updates:

    • The StrikeSelector was too eager - we added which were rarely used: IV, Theta, Vega.

    • The Statement selector didn’t have an intuitive name

    • The Indicatorsection superseded by External Data, which provides a more flexible and powerful integration with external indicator sources

  • Variable refinements:

    • Account-related variables (acc_*) saw limited use and became less relevant after introducing MesoLive

    • Timing variables (DIT, DTE) lacked sufficient resolution - they used integer days, limiting precision

A major feature we’ve long wanted to add is the Option Valuation Model used in our Risk Graph. This became the key release driver for MesoSim v3.0. To expose it accurately, we needed to resolve the DTE and DIT precision issues. Since these changes are inherently backward-incompatible, we decided to implement all other known design corrections in the same release - ensuring that customers can migrate their jobs almost entirely automatically.

The end result isn’t just a cleaner design - it’s a more capable platform.
Key highlights include:

  • Option Valuation Model (Black-Scholes-Merton) to compute theoretical option prices and Greeks for any position or leg at any point in time from the ScriptEngine

  • Solver for the valuation model to identify high/low risk points and root crossings for Greeks or PnL

  • Timing Model to target key calendar events and exploiting seasonal patterns in options trading

  • Fully integrated documentation to streamline strategy development

  • Improved performance through reduced event size and .NET 10 framework updates

  • Automated migration tool to simplify the upgrade process from earlier versions

Stay tuned for the next release and let us know what else you’d like to see in MesoSIm in the comments!

1 Like

To put the above into perspective:
Here is the v3 Strategy Definition of a Calendar. We’re calculating the Max Win, Max Loss and Break Even points using the Options Valuation Solver.

{
  "StrategyName": "MesoSim-v3-demo",
  "Description": "",
  "Backtest": {
    "Name": "generate",
    "Start": "2024-01-01T00:00:00",
    "End": "2024-01-31T00:00:00",
    "Cash": "10000"
  },
  "Symbol": "SPX",
  "Structure": {
    "Name": "Calendar",
    "Expirations": [
      {
        "Name": "front",
        "DTE": "130",
        "Min": "120",
        "Max": "140",
        "Roots": null
      },
      {
        "Name": "back",
        "DTE": "expiration_front_dte + 40",
        "Min": null,
        "Max": null,
        "Roots": null
      }
    ],
    "Legs": [
      {
        "Name": "short_call",
        "Qty": "-1",
        "OptionType": "Call",
        "ExpirationName": "front",
        "StrikeSelector": {
          "Min": "25",
          "Max": "35",
          "BidPrice": null,
          "AskPrice": null,
          "MidPrice": null,
          "StrikePrice": null,
          "Delta": "30",
          "Complex": null
        },
        "LegGroupId": "0"
      },
      {
        "Name": "long_call",
        "Qty": "1",
        "OptionType": "Call",
        "ExpirationName": "back",
        "StrikeSelector": {
          "Min": null,
          "Max": null,
          "BidPrice": null,
          "AskPrice": null,
          "MidPrice": null,
          "StrikePrice": null,
          "Delta": "-1 * pos_delta",
          "Complex": null
        },
        "LegGroupId": "0"
      }
    ]
  },
  "Entry": {
    "Schedule": {
      "AfterMarketOpenMinutes": null,
      "BeforeMarketCloseMinutes": "30",
      "Every": "day"
    },
    "Conditions": [],
    "VarDefines": {
      "_be_low": "options.model_solver(position, first_exp, underlying_price * 0.5, underlying_price * 2, pnl, zero, return_price)",
      "_be_high": "options.model_solver(position, first_exp, underlying_price * 2, underlying_price * 0.5, pnl, zero, return_price)",
      "_max_win": "options.model_solver(position, first_exp, underlying_price * 2, underlying_price * 0.5, pnl, maximize, return_value)",
      "_max_loss": "options.model_solver(position, first_exp, underlying_price * 2, underlying_price * 0.5, pnl, minimize, return_value)"
    },
    "AbortConditions": [],
    "ReentryDays": "1",
    "Concurrency": null,
    "QtyMultiplier": null
  },
  "Adjustment": null,
  "Exit": {
    "Schedule": {
      "AfterMarketOpenMinutes": null,
      "BeforeMarketCloseMinutes": "30",
      "Every": "day"
    },
    "MaxDaysInTrade": "90",
    "ProfitTarget": "pos_theta * 90 * 0.8",
    "StopLoss": "profit_target * 2",
    "Conditions": [],
    "VarDefines": null
  },
  "ExternalData": null,
  "Settings": {
    "Core": {
      "LegSelectionConstraint": "UniqueInPosition",
      "ExpirationSelectionConstraint": "AbortOnReuse",
      "Margin": null
    },
    "Sim": {
      "FillModel": "AtMidPrice",
      "SlippageAmt": "0",
      "Commission": {
        "CommissionModel": "FixedFee",
        "OptionFee": "1.5",
        "DeribitCommissionSettings": null
      },
      "PositionMonitor": {
        "TraceCollectionInterval": "Daily"
      },
      "TearsheetGeneration": "On"
    },
    "User": null
  },
  "MesoSimVersion": "3.0.3-0-g49a3158a"
}

This opens a huge door to systematically explore multi-tenor structures. Thank you!

1 Like