Instructions to use mstrasser/jeff-adapter-trading-desk with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use mstrasser/jeff-adapter-trading-desk with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Configuration Parsing Warning:In adapter_config.json: "peft.task_type" must be a string
jeff-adapter-trading-desk
Trading desk decisions. Applies a trading desk's written rules to the live order book - buy, sell or hold; size; venue; open orders; risk-off.
A LoRA adapter for jeff-base v1.3, a small open decision model
(a fine-tune of Qwen3.5-0.8B). You send a situation (the state) and questions with named options; Jeff returns a
calibrated probability for every option from one forward pass, with no generated text to parse. One Jeff server loads
the base once and any number of adapters beside it; each request picks an adapter by name ("model": "trading-desk").
Adapter page, with the full data card: jeffhub.ai/adapters/trading-desk.
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 |
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 (GGUF)
The same test, through llama.cpp: the base GGUF (mstrasser/jeff-base-gguf) plus this adapter's LoRA GGUF (mstrasser/jeff-adapter-trading-desk-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 |
Not measured yet for v1.3: calibration charts, the commonest confusions and accuracy per answer.
Source of these numbers: results/sources/v1.3/new-adapters.table.json in the JeffHub repository, also collected in jeffhub-v1.3.json.
When to use it
- 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.
When not to use it
- 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.
How to use it
The adapter runs with Jeff's server, on the main branch of firelex/jeff, on the
jeff-base v1.3 base.
git clone https://github.com/firelex/jeff && cd jeff
uv sync --no-default-groups --extra lora # add --extra cuda on NVIDIA GPUs, --extra mac on Apple silicon
uv run --no-default-groups hf download mstrasser/jeff-base --revision v1.3 --local-dir checkpoints/jeff-base
uv run --no-default-groups hf download mstrasser/jeff-adapter-trading-desk --revision v1.3 --local-dir adapters/trading-desk
JEFF_CHECKPOINT=checkpoints/jeff-base JEFF_ADAPTERS=adapters/ PORT=8765 \
uv run --no-default-groups jeff-serve # on a Mac, add JEFF_BACKEND=mlx
Every folder in adapters/ is served under its folder name; add or replace adapters while the server runs with
curl -X POST http://localhost:8765/v1/adapters/reload. Each adapter records the exact base it was trained on, and
the server refuses an adapter trained on a different one, so this adapter loads only on jeff-base v1.3 (a v1.2 adapter
does not load on v1.3). For llama.cpp, use mstrasser/jeff-adapter-trading-desk-gguf.
Request format
State (the situation), in this order:
| Key | Changes per request | What it holds |
|---|---|---|
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. |
Questions:
direction(choice): Buy, sell or hold, for momentum and mean-reversion desks. Options:buy,sell,holdsize(choice): Change the position size (volatility-target desks) or the pace of a parent order (execution desks). Options:increase,decrease,keeproute(choice): Which venue a new order goes to. Options:venue_a,venue_b,venue_c; each option names the desk's venueorder(choice): What to do with the open order named in the request. Options:cancel,amend,leaverisk_off(choice): Whether the desk must go risk-off now. Options:yes,no
Rules:
- 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: the request format guide.
Example
The request below is also in this repository as example.json.
{
"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."
}
}
}
}
curl -s localhost:8765/v1/systemone -H 'content-type: application/json' -d @adapters/trading-desk/example.json
The answer holds a probability for each option of each question. A recorded response from the v1.3 adapter is not published yet.
Files
adapter_model.safetensors,adapter_config.json: the LoRA weights (PEFT format);readout.safetensors: the adapter's own readout over the answer codes;decision_config.json: answer codes, temperature, prompt layout and the checksum of the base it was trained on;example.json: the example request above.
adapter_config.json and decision_config.json name the base as mstrasser/jeff-base, revision v1.3; the server
checks the base by the checksum of its weights.
Training
| Base | mstrasser/jeff-base, revision v1.3 (a fine-tune of Qwen3.5-0.8B) |
| Prompt layout | live-last: the fixed part of the request first, the changing state field last |
| Training code | The git_commit recorded in decision_config.json is the training machine's copy and was not published. It builds exactly the same prompt as main of firelex/jeff (from commit 6d0d7da) for a text state and for an object with at least one field; the format is in docs/v1.3-request-format.md |
| Run | 0.8b-trading-desk-20261003-1525, final checkpoint |
| Adapter files | 41.5 MB (adapter_model.safetensors and readout.safetensors) |
| LoRA GGUF for llama.cpp | mstrasser/jeff-adapter-trading-desk-gguf |
- 1.3.0 (2026-10-03): First 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).
Data card
Self-reported. The numbers come from the adapter’s own maintainers and have not been re-run by anyone else. What the levels mean
- Test set: not attached yet
- QA report: not available here yet; it will be added once sanitised
How the test set was held out. 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. Training data not published.
Which models made the data, counted on the 40,000 training rows:
| What it did | Model | Where it ran | Training 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 | own hardware (DGX B200) | 25,910 |
Wrote the market context note text_writers.market_context |
GLM 5.3 | own hardware (DGX B200) | 33,400 |
Wrote the news line text_writers.news |
GLM 5.3 | own hardware (DGX B200) | 13,058 |
Counted from each row's own record of the models that made it (the field named under each job). 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.
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 (inherited from the v1.2 recipe as 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.
Data and licence
Adapter licence: Apache-2.0.
Qwen3.5-0.8B notice: these weights were modified from Qwen3.5-0.8B by the Jeff project: jeff-base is a fine-tune of Qwen3.5-0.8B, and this adapter was trained on top of it. Qwen3.5-0.8B is Copyright 2026 Alibaba Cloud and licensed under the Apache License, Version 2.0; a copy of that licence is in LICENSE.
To confirm: whether Apache-2.0 for the adapter is compatible with the FI-2010 licence once that is confirmed.
It was trained on:
FI-2010 limit order book benchmark. Licence: Creative Commons Attribution 4.0 (CC BY 4.0), as the Etsin record lists it (open licence) · Not made by a model
Ntakaris, 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.
To confirm: the CC BY 4.0 licence, on the FI-2010 Etsin record
Synthetic desks, positions, orders and news. Licence: Released with the adapter under Apache-2.0 (made for this adapter) · Made by GLM 5.3 (own hardware), for the texts; everything else by code
400 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.
Limitations
- Tied to jeff-base v1.3. It will not load on any other base or version; the server checks the base weights' checksum.
- Jeff chooses between the options you give it. It does not write text or reason in several steps.
- Calibration was fitted on this adapter's own calibration rows. On very different data, check it again.
- Everything listed under When not to use it above.
Links
- Adapter page: jeffhub.ai/adapters/trading-desk
- Base model: mstrasser/jeff-base (revision v1.3)
- LoRA GGUF for llama.cpp: mstrasser/jeff-adapter-trading-desk-gguf
- What changed in v1.3: release notes
- Code and server: github.com/firelex/jeff
Jeff is an independent project. It uses the same request format as Jev but is not affiliated with or endorsed by TypeSafe, the makers of Jev.
- Downloads last month
- 29