Text Generation
Transformers
Safetensors
English
qwen3_5
image-text-to-text
mcp
tool-use
agentic
trading
qwen3.5
lora
conversational
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
| license: apache-2.0 | |
| base_model: Qwen/Qwen3.5-9B | |
| tags: | |
| - mcp | |
| - tool-use | |
| - agentic | |
| - trading | |
| - qwen3.5 | |
| - lora | |
| language: | |
| - en | |
| library_name: transformers | |
| pipeline_tag: text-generation | |
| # 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. | |
| ```bash | |
| 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: | |
| ```json | |
| { | |
| "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: | |
| ```yaml | |
| 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. | |