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 licenceTrained 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 field | Changes per request | What goes in it |
|---|---|---|
desk | No | The 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_context | No | The stock and the day: date, opening mid price, the morning's range and spread, and whether trading is calm, normal or active. |
market_state | Yes | The 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. |
| Question | Type | What it decides |
|---|---|---|
direction | Choice | Buy, sell or hold, for momentum and mean-reversion desks. Options: |
size | Choice | Change the position size (volatility-target desks) or the pace of a parent order (execution desks). Options: |
route | Choice | Which venue a new order goes to. Options: |
order | Choice | What to do with the open order named in the request. Options: |
risk_off | Choice | Whether the desk must go risk-off now. Options: |
- 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)import { Client, choiceQuestion } from '@jeff/client';
const jeff = new Client({ url: 'http://localhost:8765', model: 'trading-desk' });
const 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',
};
const answers = await jeff.ask(state, {
size: choiceQuestion(
{
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.',
),
});
console.log('size', answers.size.key);curl -s http://localhost:8765/v1/systemone \
-H 'content-type: application/json' \
-d '{
"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"
},
"questions": {
"size": {
"type": "choice",
"instructions": "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.",
"criteria": {
"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."
}
}
}
}'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
| Test set | Test rows | Qwen3.5-0.8B untrained | Jeff base v1.3 alone | Jeff base v1.3 + adapter |
|---|---|---|---|---|
test | 5,000 | 38.6% · 0.015 | 41.1% · 0.115 | 98.1% · 0.010 |
test5,000 test rows- Qwen3.5-0.8B untrained
- 38.6% · 0.015
- Jeff base v1.3 alone
- 41.1% · 0.115
- Jeff base v1.3 + adapter
- 98.1% · 0.010
Each cell: accuracy · calibration error (ECE; lower is better, 0 is perfect).
By group
| Group | Rows | Qwen3.5-0.8B untrained | Jeff base v1.3 alone | Jeff base v1.3 + adapter |
|---|---|---|---|---|
| decision: direction | 1,000 | 35.8% | 34.9% | 99.9% |
| decision: order | 1,000 | 34.1% | 37.1% | 100.0% |
| decision: risk_off | 1,000 | 55.7% | 63.2% | 100.0% |
| decision: route | 1,000 | 34.0% | 32.8% | 95.3% |
| decision: size | 1,000 | 33.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
| Test set | Full precision | Q8_0 | Q4_K_M |
|---|---|---|---|
test | 98.1% · 0.010 | 98.1% · 0.010 | 97.8% · 0.011 |
Source: results/sources/v1.3/new-adapters.table.json
Model card
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.
| What it did | Model | Where it ran | Rows |
|---|---|---|---|
Rewrote the desk rules in one of five styles (checked by code to keep every number and rule) text_writers.desk | GLM 5.3 | local | 25,910 |
Wrote the market context note text_writers.market_context | GLM 5.3 | local | 33,400 |
Wrote the news line text_writers.news | GLM 5.3 | local | 13,058 |
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.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.
