Skip to content
JeffHub
FinanceOfficialVersion 1.3.0

trading-deskTrading desk decisions

Applies a trading desk's written rules to the live order book - buy, sell or hold; size; venue; open orders; risk-off.

Data: Real FI-2010 order books (Nasdaq Helsinki, June 2010) plus synthetic desks; code fixes every label, and GLM 5.3 writes desk rules, context and news.

Licence, in plain words

The adapter: Apache-2.0. Every data source has an open licence or was made for this adapter.

Every data source and its licence

Trained on Jeff v1.3. Adapters are tied to the exact base they were trained on. What changed in v1.3

Use it when

  • An automated desk has written rules (entry levels, clip size, position limit, venues, order handling, risk-off triggers) and you want each rule applied to the live market state in milliseconds.
  • Your rules can be stated in text, per desk; the adapter reads the desk definition, so thresholds and venues can be your own.
  • You want a calibrated probability per action, so uncertain decisions can go to a person or a slower check.

Not a good fit when

  • You want a forecast or a trading strategy. The adapter applies the rules you write; it does not predict prices or judge whether a rule is a good one.
  • Your decisions depend on data the state does not show, such as other instruments or a portfolio's risk model. Put the facts in the state, or decide in code.
  • The rules are fixed and simple enough to code directly. Then code them; it is cheaper and exact.
  • Your market differs a lot from the training data (one exchange, five stocks, June 2010). Test it on your own data first.

Request format

The state is an object with these fields, in this order. Only market_state changes from request to request, so it comes last and the rest can be prepared in advance.

State fieldChanges per requestWhat goes in it
deskNoThe desk definition: strategy and entry rule, clip size, position limit, spread and cut-off filters, order handling, risk-off triggers, the instrument, the venues with fees and latencies, and the routing rule.
market_contextNoThe stock and the day: date, opening mid price, the morning's range and spread, and whether trading is calm, normal or active.
market_stateYesThe live state: time, order book, spread, mid and its average, order-flow imbalance, realised volatility, recent trades, displayed size per venue, position and P&L, open orders, parent order, news, and the request.
QuestionTypeWhat it decides
directionChoiceBuy, sell or hold, for momentum and mean-reversion desks.

Options: buy, sell, hold

sizeChoiceChange the position size (volatility-target desks) or the pace of a parent order (execution desks).

Options: increase, decrease, keep

routeChoiceWhich venue a new order goes to.

Options: venue_a, venue_b, venue_c; each option names the desk's venue

orderChoiceWhat to do with the open order named in the request.

Options: cancel, amend, leave

risk_offChoiceWhether the desk must go risk-off now.

Options: yes, no

  • Ask one question per request, the one the request line names; each was trained with its own fixed instructions.
  • Keep the desk definition and market context the same across requests, and put the live state last, so the unchanging part can be prepared in advance.
  • Show the numbers the rules need, rounded as the rule states them; the adapter applies the rule to what it sees.

General rules for every request are in the request format guide.

Example

The same request three ways. It assumes a Jeff server on your machine with this adapter loaded (see Install).

from jeff import Client
from jeff.client import choice_question

jeff = Client("http://localhost:8765", model="trading-desk")

state = {
    "desk": "Desk Crest Vol Target trades Outokumpu shares (OUT1V), strategy: volatility-targeted position holding.\nDesk rulebook:\n* Instrument: Finnish stainless-steel producer, listed on Nasdaq OMX Helsinki, traded in euros; tick size EUR 0.01; continuous trading from 10:00 to 18:25 Helsinki time; typical spread 2 ticks; typical displayed size at the best price about 1,226 shares.\n* Standard order size (one clip): 300 shares. Position limit: the absolute position (long or short) may not exceed 3,300 shares.\n* Volatility is the realised volatility over the long window (200 updates). Cut the position by one clip (decrease) when the unrealised loss on the position is EUR 500 or more, or when volatility is 38.5 bps or more. Otherwise add one clip (increase) when volatility is below 34 bps and the absolute position after adding stays within the position limit. Otherwise keep the size.\n* Go risk-off when any of these holds: realised volatility over the long window (200 updates) is 47 bps or more; the day's P&L is a loss of EUR 3,000 or more; the absolute position is above the position limit; or news of the chief executive leaving, a takeover offer or a trading halt arrives.\n* Venues: Tapio Dark: fee 0.35 bps of the traded value, latency 0.3 ms; Helmi Cross: fee 0.3 bps of the traded value, latency 0.5 ms; Kallio Pool: fee 0.2 bps of the traded value, latency 2.5 ms.\n* Routing: send a new order to the cheapest venue (lowest fee) whose displayed size at the best price can fill the whole order. If the order is marked urgent, use the fastest venue (lowest latency) that can fill the whole order instead. If no venue can fill the whole order, use the venue with the largest displayed size.",
    "market_context": "Market context for Outokumpu on 14 June 2010: the session opened with a mid price of 13.415. Up to 11:15:45 the price drifted higher between 13.380 and 13.555, with a typical spread of 1 ticks. Trading conditions this morning: normal.",
    "market_state": "[11:18:30] BOOK bids 13.51 x 3,114; 13.50 x 1,020; 13.49 x 1,249; 13.48 x 6,500; 13.47 x 4,609 | asks 13.54 x 3,040; 13.55 x 2,120; 13.56 x 3,241; 13.57 x 3,200; 13.58 x 6,178\nspread 3 ticks | mid 13.525 | avg mid (100 updates) 13.508 | deviation +1.7 ticks\nimbalance: best 1 level +0.01 | best 3 levels -0.22 | best 5 levels -0.04\nrealised vol: short (50 upd) 15.7 bps | long (200 upd) 35.1 bps | signal flat\nmid path (every 50 upd): 13.505 / 13.550 / 13.505 / 13.505 / 13.525\ntrades: 11:17:02 seller took 140 at 13.50; 11:17:07 buyer took 6,290 at 13.52; 11:17:13 buyer took 3,030 at 13.52\nvenues at best (bid / ask): Tapio Dark 176 / 267; Helmi Cross 424 / 309; Kallio Pool 2,514 / 2,464\nposition: short 2,400 shares, average entry 13.681 | unrealised P&L +EUR 374; day P&L +EUR 3,226\nopen orders: none\nnews: (11:17) Economic data: US weekly jobless claims at 44.0\nREQUEST: position size review",
}

answers = jeff.ask(state, {
    "size": choice_question(
        {
            "increase": "Increase: add one clip to the position, or speed up the parent order.",
            "decrease": "Decrease: cut the position by one clip, or slow down the parent order.",
            "keep": "Keep the current size or pace.",
        },
        "You are the decision step of an automated trading desk. A volatility-target desk sizes its position from realised volatility and the unrealised loss on its position; an execution desk paces a client parent order against its schedule and its limit price. Apply the sizing or pacing rule in the desk definition to the live market state.",
    ),
})
print("size", answers.choice("size").key)

A real response from this adapter appears here when it is released.

Results

On this adapter's held-out test set, never trained on, scored three ways on the same rows: the untrained model Jeff is built from, the Jeff v1.3 base alone, and the base with this adapter. Questions have 2 to 3 options. As of 2026-10-05. All adapters

  • test5,000 test rows
    Qwen3.5-0.8B untrained
    38.6% · 0.015
    Jeff base v1.3 alone
    41.1% · 0.115
    98.1% · 0.010

Each cell: accuracy · calibration error (ECE; lower is better, 0 is perfect).

By group
trading-desk: accuracy by group
GroupRowsQwen3.5-0.8B untrainedJeff base v1.3 aloneJeff base v1.3 + adapter
decision: direction1,00035.8%34.9%99.9%
decision: order1,00034.1%37.1%100.0%
decision: risk_off1,00055.7%63.2%100.0%
decision: route1,00034.0%32.8%95.3%
decision: size1,00033.3%37.3%95.5%

With llama.cpp

The same test, through llama.cpp: the base GGUF plus this adapter's LoRA GGUF, with the temperature refitted for each format. Running Jeff with llama.cpp

trading-desk: accuracy at full precision and in each GGUF format
Test setFull precisionQ8_0Q4_K_M
test98.1% · 0.01098.1% · 0.01097.8% · 0.011

Source: results/sources/v1.3/new-adapters.table.json

Model card

Finance · official

trading-desk: how it was made

How it was made

In short: Real FI-2010 order books (Nasdaq Helsinki, June 2010) plus synthetic desks; code fixes every label, and GLM 5.3 writes desk rules, context and news.

  • Test set: Whole trading days and whole desks held out. Training uses days 1-6 (1 to 8 June 2010) with 275 desks; the test uses days 9-10 (11 and 14 June) with 75 other desks. No order book, desk, desk text, market context or news item is shared between training and test.
  • Training data: not published.
  • Training mixed in a replay sample of the Jeff base model's own training data: 4,000 rows, about 10% on top of the adapter's 40,000 (a precaution; its effect has not been measured).
  • Order books, prices, sizes, spreads, imbalance and volatility are the real FI-2010 values (five Helsinki stocks, ten trading days). Desks, venues, positions, orders, news and the clock are generated by code with fixed seeds; venue names are invented.
  • About 44% of rows are hard cases built on purpose, such as an imbalance just either side of the entry level or a position one clip under its limit.
  • In a blind check, GLM 5.3 answered 200 random test rows without the label and agreed on 197; in all three disagreements the label follows the written rule.
  • Training mixes in about 10% of the base model's own training data.
Which models made the data, counted on the 40,000 training rows
What it didModelWhere it ranRows
Rewrote the desk rules in one of five styles (checked by code to keep every number and rule) text_writers.deskGLM 5.3local25,910
Wrote the market context note text_writers.market_contextGLM 5.3local33,400
Wrote the news line text_writers.newsGLM 5.3local13,058
Counted from each row's own record of the models that made it. A row counts once under every job that names a model, so the counts do not add up to the total. Every label is computed by code from the values shown in the row, using the desk's written rules. GLM never sees or sets a label. The live market state (book, imbalance, volatility, position, orders) is never reworded by a model.

Data and licence

Adapter: Apache-2.0

  • FI-2010 limit order book benchmarkCreative Commons Attribution 4.0 (CC BY 4.0), as the Etsin record lists itNot generated by a modelNtakaris, Magris, Kanniainen, Gabbouj and Iosifidis (2018), "Benchmark dataset for mid-price forecasting of limit order book data with machine learning methods", Journal of Forecasting 37(8). Published on Fairdata/Etsin (urn:nbn:fi:csc-kata20170601153214969115). Order books for five Nasdaq Helsinki stocks, 1 to 14 June 2010.
  • Synthetic desks, positions, orders and newsReleased with the adapter under Apache-2.0Generated by GLM 5.3 (own hardware), for the texts; everything else by code400 desk definitions, venues, positions, open orders, parent orders and news events generated by code with fixed seeds. Desk rules, market context notes and news lines were rewritten by GLM 5.3 and checked by code.

Check it yourself

Changelog

  1. 1.3.0 · 2026-10-03First release, trained on Jeff v1.3 with the live-last prompt layout (LoRA rank 16, one epoch, about 10% of the base model's own training data mixed in). Not yet on Hugging Face.

Comments

Comments open when JeffHub launches. They will live in the registry repository's GitHub Discussions, one thread per adapter; you sign in with GitHub, and JeffHub stores no accounts.