LEARN/AGENTS

Agents

An agent is any object with an act method. The harness gives it an observation and takes back target weights.

Three kinds of agent use this page

An execution algorithm A TWAP, a VWAP, an iceberg. You write the logic in Python.
A trained policy A reinforcement-learning policy through the Gymnasium environment.
An LLM agent A model that reads the observation and answers with weights at each step.

An LLM agent trades inside the market from here. A model that studies the market from outside uses the MCP server instead, and writes no code at all.

class Mine:
    def act(self, obs):
        # target weights, one per name
        return {"AAA": 0.2, "AAB": -0.1}

scores = tf.evaluate(
    {"mine": Mine()}, seed=7,
    universe=u, days=10)

scores["mine"].return_pct
scores["mine"].impact_bps

Three rules of the harness

You return target weights Weights in [-1, 1], one per name. The harness turns them into orders, so a policy does not learn each price range first.
The market answers back Orders match against the engine's own depth. Reward is measured after the market moves, so it already carries the cost of your own footprint.
The seed owns the randomness Give the same agent the same seed and universe, and you get the same run.

The observation is narrow on purpose

Everything in it is information available to a trader inside the simulated market. Nothing in it is something only the simulator knows.

The agent sees

prices the order book your position your cash the step number

The agent never sees

the true mispricing fair value tomorrow's prices other agents' orders

The Oracle is the exception. It reads the true mispricing and declares itself, which is why it is a reference and not a competitor.

step counts the whole run, not the day. A ten-day run at three decisions a day ends at step 30.

Compare agents

ONE MARKET EACH, NOT ONE SHARED BOOK

Ten agents in one evaluate call get ten private engines, built from the same seed and roster. Each agent pays its own impact and sees nobody else's orders. That is what makes the comparison clean. It is also why there is no arena. To make agents take each other's depth, drive one engine yourself and combine their flow into each tick.

Run the pair across twelve seeded markets. Then read the pooled number and the paired number against each other. Here is the measurement the docs publish.

ranking = tf.rank(
    lambda: tf.reference_agents(seed=3),
    seeds=range(12), universe=u,
    days=10, workers=4)

ranking.separation("mean_reversion",
                   "momentum")
{'wins': 9, 'losses': 3,
 'ties': 0, 'p_value': 0.1460}

Twelve markets, one square each

mean-reversion won 9 momentum won 3

The squares show the tally, not the seed order. Which seed fell which way is in the agents docs.

3x pooled capture Mean-reversion at +0.783 against momentum at +0.259, across the grid.
0.15 sign-test p-value A 9 to 3 split on twelve paired markets. The sign test does not call that settled.
8 / 12 single-seed hit rate How often one market picks the pooled leader. The other four crown momentum three times and buy-and-hold once.

Pooled, mean-reversion leads by three times. Paired, 9 to 3 at p = 0.15 is not a separation. Both numbers are true and they answer different questions: how much it won by, and how often. Report the pair.

The shipped baselines

Five reference agents ship. Each one is also a StrategySpec, so you can cite it as data.

hold Buy the roster on day one and do nothing. The number every other agent must beat.
random Weights from its own seed, which lives in the spec. The noise floor.
momentum Buys what rose. Pools at +0.259 on the published grid. Read the herding dial caveat below before you trust it.
mean_reversion Buys what fell. Pools at +0.783 on the published grid, and it beats the Oracle on 5 of the 12 markets.
oracle Reads the true mispricing, and gets no extra capital for it. A reference point, not a ceiling: agents out-earn it on 5 of 12 markets.

Read this before you conclude

Momentum can work here for a reason real markets do not supply

Returns trend, because the mispricing process has a herding term with a dial on it. pt-v14 turns that dial well down. momentum_theta sits at 0.0186 and return autocorrelation at lag one reads +0.0114, against a real band of -0.08 to 0.06. pt-v1 ships the same knob at 0.25 and measures +0.249. The dial exists either way, and real markets have no equivalent.

No counterparty adapts to you

You trade against a market maker and aggregate flow. Orders arrive instantly and there is one book per name. Nothing in the market learns your pattern and front-runs it.

All pages