The risk outline is the core analytical innovation of the project. Rather than applying hard-codedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/backtest-kit/backtest-ollama-crontab/llms.txt
Use this file to discover all available pages before exploring further.
if statements in application code, it passes each parsed trading signal to a locally-running Ollama LLM together with pre-computed market metrics and recent candle data. The LLM is instructed to apply exactly two empirically-derived rules — nothing more — and return a structured verdict. This design keeps the decision logic auditable: every call is logged with a description and step-by-step reasoning field, and the full response is dumped to ./dump/outline/risk for post-analysis.
The Two Rules
The system prompt (RISK_PROMPT) instructs the LLM to evaluate two skip rules and one default case, in order:
Rule 1 — Sleeping-coin SHORT (skip)
Condition:
direction = SHORT AND avgRangePct < 0.07%Action: "skip"Rationale: A “sleeping” asset has thin liquidity and an unusually narrow 1-minute candle range. A single large market-maker candle can sweep all stop-loss orders above the entry zone — exactly where channel SHORT subscribers are positioned. The channel’s signal becomes a stop-hunt trigger rather than an edge.Rule 2 — Knife-catching LONG (skip)
Condition:
direction = LONG AND momentum24hPct < -1%Action: "skip"Rationale: Buying into a market that has already dropped more than 1% over the past 24 hours puts subscribers on the wrong side of momentum. The market continues downward, the stop-loss is triggered, and the channel has effectively sold the top to its audience.action is determined strictly by the two rules applied to the pre-computed metrics avgRangePct and momentum24hPct. The sure_level and confidence fields are audit fields recorded for post-analysis — they never affect the trading decision. The strategy in jan_2026.strategy.ts follows or skips solely based on riskAction.Pre-computed Metrics
commitMetricsHistory() fetches the last 1440 1-minute candles (24 hours of history) via getCandles(symbol, "1m", 1440) and computes two scalar metrics that are passed to the LLM as a user message:
| Metric | Formula | Meaning |
|---|---|---|
avgRangePct | mean((high − low) / close × 100) over 1440 1m candles | Average intra-candle volatility as a percentage of close price — a proxy for liquidity depth. |
momentum24hPct | (last close − first open) / first open × 100 | Net 24-hour price change — a directional momentum indicator. |
Candle Context
Two advisors supply additional candle tables that the LLM uses to populate the audit fields (sure_level, confidence). Both are fetched via ask(symbol, advisorName) and pushed into the conversation history before the metrics message.
StockData1mAdvisor (AdvisorName.StockData1mAdvisor)
Fetches the last 240 1-minute candles (4 hours of history) and formats them as a markdown table with columns: #, Time, Open, High, Low, Close, Volume, Change %, Volatility %, Body %.
StockData15mAdvisor (AdvisorName.StockData15mAdvisor)
Fetches the last 32 fifteen-minute candles (8 hours of history) and formats them in the same markdown table structure.
Outline Definition
The outline is registered withaddOutline() from agent-swarm-kit. The full call structure is:
Conversation history order
The history is assembled in this exact sequence before the model is called:- System —
RISK_PROMPT(role description, rules, output requirements) - User → Assistant OK — 1-minute candle markdown table
- User → Assistant OK — 15-minute candle markdown table
- User → Assistant OK —
avgRangePct,momentum24hPct,candlesCount - User → Assistant — draft signal (symbol, direction, targets, stop-loss)
- User — final instruction to apply rules and return structured output
Validations
Five validators run against every LLM response before it is accepted:| # | Field | Rule |
|---|---|---|
| 1 | action | Must be "skip" or "follow" |
| 2 | sure_level | Must be one of "low", "low_medium", "medium", "medium_high", "high" |
| 3 | confidence | Must be "reliable" or "not_reliable" |
| 4 | description | Must be a string with at least 30 characters |
| 5 | reasoning | Must be a string with at least 80 characters |
LLM System Prompt
RISK_PROMPT is written in Russian (the channel language) and instructs the model in the following key points:
- Role: Scam signal detector for Telegram trading channels. The sole task is to return
action: "follow"oraction: "skip". - Available data: Pre-computed metrics (
avgRangePct,momentum24hPct), 1-minute candles (4 h), 15-minute candles (8 h), and the draft signal. - Decision rules: Apply Rules 1 and 2 literally using the pre-computed metric values. No intuition, no trend analysis, no news. If neither rule fires, return
"follow". - Audit fields:
sure_level(evidence of manipulation in candle structure) andconfidence(reliability of available data) are filled honestly but do not affectaction. - Output format:
action,sure_level,confidence,description(2–3 sentences citing the rule and numbers),reasoning(a single flat string with steps separated by\n— not a JSON object or array).
Response Contract
The Zod schema that enforces the LLM’s response structure:zodResponseFormat(RiskOutlineFormat, "risk_assessment") call converts this schema into the structured-output format expected by the Ollama API.
Completion Backends
Two completion backends are available. The risk outline usesOllamaOutlineToolCompletion (tool-calling mode):
| Setting | Value |
|---|---|
| Model | gpt-oss:120b |
| Max inner attempts per call | 3 |
| Outer retry count | 5 |
| Retry delay | 5 000 ms |
| Request timeout | 300 000 ms (5 minutes) |
jsonrepair to fix common JSON formatting errors (trailing commas, unquoted keys, truncated strings) before passing the response to Zod validation. This significantly reduces the rate of retries caused by minor model output formatting issues.