LEARN/CORE CONCEPTS

Core concepts

Three things define a run. Two of them do something you can not expect when the market starts to move.

import tradefloor as tf

universe = tf.Universe.random(108, seed=7)
macro = tf.Macro(federal_funds_rate=0.025, corporate_bond_yield=0.052, vix=16.0)
engine = tf.Engine(seed=42, universe=universe, macro_state=macro)

Roster order changes the market

Universe subclasses list. The engine walks the instruments in index order and draws random numbers as it goes. A re-sorted roster is therefore a different market from the same seed.

What a reversed roster costs

On Universe.random(20, seed=11) at sim seed 42, AAA closes day 5 at:

143.03 roster order
134.88 reversed

Same names, same fundamentals, same seed. A sort of your tickers upstream does this without a warning.

There are two seeds

The universe seed Picks the fundamentals. The generator assigns tickers and sectors by position. random(40, seed=1) and random(40, seed=99) therefore share every name and every sector. They agree on the fundamentals of none of the forty.
The simulation seed This seed picks the market. Hold the universe fixed and change this one. That is the standard setup to find how much of a result was luck.

The economy moves on its own

The Macro that you give the engine is the state on day zero. Every close advances the chain. The economy updates, the cycle can turn, and the central bank acts. If you want a frozen economy, you must ask for one.

How often each field takes a new value

120 days, Universe.random(20, seed=11), sim seed 42
vix 118 of 120 days
gdp_growth 6 values
inflation_rate 4 values
corporate_bond_yield 3 values
fundamental_value 3 per instrument
federal_funds_rate 2 values
VIX moves nearly every day. The policy fields step on the central bank's meeting calendar. Fair value reprices when the discount rate moves at a meeting. In that run it moved on day 45 and day 96. A run that crosses a meeting is therefore not a stationary experiment.
Pinning a field does not freeze it

A pin replaces the endogenous step for that field one time. The chain then continues from the pinned value. Pin vix=30.0 after day 3. The next four days read:

30.00 pinned 22.75 23.62 23.89 19.30

The series pulled back toward its mean. It did not hold. For a day-by-day exogenous series, pin the field every day, or drive a scenario.

Four ways to build a universe

tf.Universe.random(108, seed=7)          # generated, plausible per sector
tf.Universe([tf.Instrument(...), ...])   # your own roster
tf.Universe.from_edgar(snapshot)         # real SEC fundamentals
tf.Universe.from_json(saved)             # one you saved with to_json

universe.fingerprint                     # sha256 over the roster, order included

The generator fills twelve sectors round-robin, so a generated roster is more balanced than any real index. That costs nothing over one year. It shows in the second year, as the envelope states.

All pages