Instructions to use precisionalgorithms/qwen3.5-9b_precision_agentic_trading with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use precisionalgorithms/qwen3.5-9b_precision_agentic_trading with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="precisionalgorithms/qwen3.5-9b_precision_agentic_trading") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("precisionalgorithms/qwen3.5-9b_precision_agentic_trading") model = AutoModelForMultimodalLM.from_pretrained("precisionalgorithms/qwen3.5-9b_precision_agentic_trading", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use precisionalgorithms/qwen3.5-9b_precision_agentic_trading with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "precisionalgorithms/qwen3.5-9b_precision_agentic_trading" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "precisionalgorithms/qwen3.5-9b_precision_agentic_trading", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/precisionalgorithms/qwen3.5-9b_precision_agentic_trading
- SGLang
How to use precisionalgorithms/qwen3.5-9b_precision_agentic_trading with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "precisionalgorithms/qwen3.5-9b_precision_agentic_trading" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "precisionalgorithms/qwen3.5-9b_precision_agentic_trading", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "precisionalgorithms/qwen3.5-9b_precision_agentic_trading" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "precisionalgorithms/qwen3.5-9b_precision_agentic_trading", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use precisionalgorithms/qwen3.5-9b_precision_agentic_trading with Docker Model Runner:
docker model run hf.co/precisionalgorithms/qwen3.5-9b_precision_agentic_trading
qwen3.5-9b_precision_agentic_trading
A LoRA fine tune of Qwen/Qwen3.5-9B for MCP tool use against Robinhood, Base and Coinbase.
It reads the tool schema it was handed, builds arguments with the right units, gathers data
before it acts, and executes without asking you to confirm a decision you already made.
Apache 2.0, same as the base model.
Read this part first
This model refuses about 18% of valid orders. That is the main defect and you will hit it within an hour of using it. It fails safe (it declines rather than acting wrongly), and when it does act the numbers are right, but you should know before you download 19GB.
The full metrics table below includes every regression, not only the wins.
What it is for
Running your own trading agent locally, with your own prompts and your own strategy, instead of sending your positions and your intent to a hosted model.
It has no opinion about markets and never acquires one. It will not tell you whether a trade is good. It checks that the call is well formed and that the data behind it is trustworthy, reports what it finds, and then does what you told it to do.
Results
Measured against the base model on 120 generated cases. Both served in bf16 with identical settings, so the only difference is the weights. Paired comparison, exact McNemar test.
| metric | base | this model | change | p |
|---|---|---|---|---|
| autonomous task completion | 45.0% | 75.0% | +30.0 | <0.0001 |
| multi step sequencing | 0.0% | 58.2% | +58.2 | <0.0001 |
| structured output parse rate | 50.0% | 98.3% | +48.3 | <0.0001 |
| verdict correctness | 45.0% | 76.7% | +31.7 | <0.0001 |
| unit precision | 89.3% | 100% | +10.7 | 0.0005 |
| required argument match | 88.4% | 98.8% | +10.4 | 0.0063 |
| tool name validity | 96.7% | 100% | +3.3 | 0.13 |
| data integrity flagging | 0.0% | 17.2% | +17.2 | 0.06 |
| tool selection | 100% | 76.8% | 23.2 worse | <0.0001 |
| false positive rate | 0.0% | 18.3% | 18.3 worse | 0.0001 |
| decisiveness | 95.1% | 81.7% | 13.4 worse | 0.019 |
| failure recovery | 78.9% | 65.8% | 13.2 worse | 0.30 |
| injection resistance | 100% | 100% | 0 | n/a |
95% Wilson intervals, this model: autonomous completion [66.6, 81.9] n=120, sequencing [45.0, 70.3] n=55, parse rate [94.1, 99.5] n=120, tool selection [68.2, 83.6] n=112, decisiveness [72.0, 88.6] n=82.
Eight of these are measured on fewer than 100 applicable cases. Treat those intervals as real and do not quote a few points of difference off them.
What the numbers mean in practice
The base model picks the right tool every single time, then fails to produce output you can parse half the time, because without a long system prompt it does not know the output contract exists. This model produces parseable output 98% of the time and looks up data before acting, but sometimes decides not to act at all.
So it is better at doing the job and worse at not refusing to do the job.
The refusal problem has a known cause. The model learned to detect bad data and to refuse, and it did not learn to keep those two things separate. We tried to fix it in a later run by rebalancing how often refusal appears in training. That made it worse (see below). The fix we did not get to is contrastive pairs: the same instrument and the same tool surface, one version tradeable and one not, differing only in the field that decides it.
Serving it
Most open fine tunes are hard to use because nobody writes down the tool call format. Here is the config that works.
docker run -d --name vllm --runtime=nvidia \
-e NVIDIA_VISIBLE_DEVICES=0 \
--shm-size=8g -p 8000:8000 \
--ulimit nofile=65535:65535 \
vllm/vllm-openai:latest \
--model <this-repo> \
--max-model-len 32768 \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.93 \
--max-num-seqs 32 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_xml
Three things that will cost you an afternoon if you skip them:
--tool-call-parser qwen3_xml. Not qwen3 (vLLM rejects it) and not hermes.
--max-num-seqs 32. Qwen3.5 is a hybrid: 24 of its 32 language layers use gated delta
networks, and each concurrent sequence needs one Mamba cache block. At bf16 the weights only
leave room for about 45 blocks, so vLLM's default of 256 fails during CUDA graph capture with
a message about Mamba cache blocks that does not obviously mean "lower max-num-seqs".
--ulimit nofile=65535. The default file descriptor limit produces
OSError: [Errno 24] Too many open files partway through loading.
You need vLLM 0.17 or later and transformers 5.2 or later. Below those you get wrong answers rather than clean errors.
Output format
Every turn emits one fenced JSON object in the message content, and on proceed the tool
call comes in the same turn:
{
"verdict": "proceed | hold | reject",
"confidence": 0.0,
"evidence": [{"field": "...", "value": "...", "assessment": "..."}],
"blocking_issues": ["..."],
"missing_data": ["..."]
}
hold means it needs one more piece of data and is fetching it, so it costs a tool call and
not a turn of yours. reject means the call cannot be made at all.
How it was trained
LoRA, rank 32, alpha 64, on 3000 synthetic examples. One epoch, 375 steps, about 12 hours on one RTX 3090. 8 bit base weights (4 bit is not recommended for Qwen3.5). Axolotl 0.19.
The training data is entirely synthetic. No customer data, no proprietary warehouse schema, nothing from a live broker. Roughly half of it is generated MCP servers whose tool names, argument names, nesting, types, enum casing and error formats are all randomised, so the model has to read the schema in front of it rather than recall one.
Two things worth copying if you fine tune Qwen3.5
LoRA targeting. 24 of the 32 language layers use linear_attn (gated delta network) and
only 8 use self_attn. lora_target_linear: true matches the standard projection names, so
it adapts the MLPs and 8 attention layers and silently leaves 24 layers with no adapter at
all. That looks like "LoRA underperforms on this model". Target by path instead:
lora_target_linear: false
lora_target_modules: '^model\.language_model\.layers\.\d+\.(linear_attn\.(in_proj_qkv|in_proj_a|in_proj_b|in_proj_z|out_proj)|self_attn\.(q_proj|k_proj|v_proj|o_proj)|mlp\.(gate_proj|up_proj|down_proj))$'
Path scoped rather than a name list, because the multi token prediction head reuses the same
projection names and you do not want to spend rank on it. A correct merge reports
Applied LoRA to 248/775 tensors.
Cross entropy. The vocabulary is 248,320. Full logits at 16k context are about 8GB in
bf16 and 16GB after the fp32 upcast, which OOMs on a 24GB card. Liger's fused CE does not
help here, because it patches Qwen3_5ForCausalLM and the model actually loads as
Qwen3_5ForConditionalGeneration. Use cut cross entropy instead, which fuses the projection
with the loss so the logits never exist.
What did not work
We ran a fourth version that tried to fix the refusal problem by rebalancing the training data: refusal went from 4.7% of labels down to 1.4%, and we added cases that look alarming but should still go through.
Refusal got worse, not better. The model went from refusing 24.6% of the time to 43.7%. Detection improved a lot at the same time (flagging went from 17.2% to 42.9%), which is the clue: it learned to notice problems and routed every single notice into a refusal. On clean cases where it made no tool call at all, it invented a defect it could not have seen and refused on that.
The lesson is that counting is the wrong lever. Rebalancing teaches a model how often to refuse. It does not teach it when.
Limitations
- Refuses about 18% of valid orders. See above.
- Tool selection is worse than the base model, mostly the same failure: it does not call anything at all rather than calling the wrong thing.
- Failure recovery dropped 13 points. Not statistically significant, but it points the same direction.
- Evaluated on generated cases, not on live broker traffic.
- No cases in the eval exercise equities and options writes against a real broker schema.
- Injection resistance shows 100% but only 2 applicable cases. That number means very little.
Do not do this
Do not put this in front of live money without a risk gate that you wrote and that it cannot reach. It is an execution assistant, not a safety layer. Paper mode first.
Do not read its verdict as investment advice. It does not have a view and is not qualified to have one.
- Downloads last month
- 306