Backtest API Reference
Complete reference for the SentimenTrader Backtest API. Submit strategy parameters as structured JSON, monitor execution via task polling, and retrieve backtest results â covering 4 rule types, 16 condition operators, and 3 signal categories.
// 1. Copy this. 2. Replace email & password. 3. Run. curl https://st-tools.sentimentrader.com/backtest/start_backtest \ -u "you@example.com:your-password" \ -H "Content-Type: application/json" \ -d '{ "symbol": "SPY", "entry": { "rule_type": "SingleCondition", "condition": { "signal": { "name": "Short Term Combined Model" }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }, "exit": { "rule_type": "RiskControlOnly" } }'
You'll get a task_id back immediately. Poll GET /backtest/status/{task_id} for results. Only 3 fields are required â the other 12 parameters auto-fill with sensible defaults.
Try /backtest/validate â to preview filled params without submitting. Full request example â
API Endpoint
curl https://st-tools.sentimentrader.com/backtest/start_backtest \ -u "user@example.com:password" \ -H "Content-Type: application/json" \ -d '{ "symbol": "SPY", "name": "Short Term Combined Model Strategy", "benchmark": "SPX", "direction": "Long", "frequency": "Daily", "strategy": "Single", "model": "cash", "capital": 100000, "capital_alloc": "1.000000", "commission": "0.0000", "slippage": "0.0000", "start_date": "1800-10-01", "trade_price": 2, "risk_control": "//21", "entry": { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": { "extreme_optimism": "10", "extreme_pessimism": "-10" } }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }, "exit": { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": { "extreme_optimism": "10", "extreme_pessimism": "-10" } }, "rule": { "comparison_type": "SV", "type_name": ">", "comparison_value": "13.5" } } } }'
// 202 Accepted { "message": "Backtest task created successfully", "task_id": "a3f8c1d2-7b4e-4f6a-9c8d-1e2f3a4b5c6d" }
// StrategyParams schema type StrategyParams = { symbol: string // required â trading ticker name: string // strategy label direction: string // "Long" | "Short" (default: "Long") frequency: string // "Daily" | "Hourly" | "Weekly" | "Monthly" capital: number // initial capital (default: 100000) trade_price: number // 0=Next Open, 1=Next Close, 2=Current Close (default: 2) risk_control: string // "{stopLoss}/{takeProfit}/{maxDays}" (default: "//21") entry: RuleBlock // entry rule definition exit: RuleBlock // exit rule definition }
Authentication
HTTP Basic Auth. All endpoints except the public whitelist require authentication.
# HTTP Basic Auth curl https://st-tools.sentimentrader.com/backtest/start_backtest \ -u "email@example.com:password"
import requests resp = requests.post( "https://st-tools.sentimentrader.com/backtest/start_backtest", auth=("email@example.com", "password"), json=params )
// Authentication headers Header Value Authorization Basic base64(email:password) Content-Type application/json
/health, /auth-info, /docs, /openapi.json, /redoc, /backtest/tutorialCore Strategy Parameters
Fundamental parameters that define the trading strategy identity and scope.
For this symbol, enter when <condition>, exit when <condition>. Entry and exit share identical structure â only the trigger timing differs. Details: Rule Definition â
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Required | ||||
symbol The trading instrument ticker. This is the only required parameter â all others have defaults. Used both for price data retrieval and as the backtest universe. | string | required | Trading ticker symbol | "SPY", "AAPL", "XBTUSD" |
Auto-Defaulted | ||||
| strategy | string | auto | Strategy type. Default: "Single" | "Single" |
| direction | string | auto | Trade direction. Default: "Long" | "Long" / "Short" |
| frequency | string | auto | Candle period. Default: "Daily" | "Daily", "Hourly", "Weekly" |
| benchmark | string | auto | Performance benchmark. Default: "SPX" | "SPX", "HSI" |
Optional | ||||
| name | string | optional | User-defined strategy name | "Short Term Combined Model Strategy" |
| description | object | optional | Strategy description container | {"Introduction": "...", "Rules": "..."} |
Backtest & Capital Configuration
| Parameter | Type | Default | Description | Example |
|---|---|---|---|---|
Date Range | ||||
| start_date | string | "1800-10-01" | Backtest start (YYYY-MM-DD) | "1800-10-01" |
| end_date | string | current date | Backtest end date | "2026-06-01" |
Capital | ||||
| capital | number | 100000 | Initial capital | 100000 |
| capital_alloc | string | "1.000000" | Per-trade allocation (string) | "1.000000" |
| commission | string | "0.0000" | Per-trade commission (string) | "0.0000" |
| slippage | string | "0.0000" | Per-trade slippage (string) | "0.0000" |
Advanced Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
trade_price Determines when the trade is executed relative to the signal bar. Current Close (2) is the frontend default â trade fills at the close of the bar where the signal fires. | number | 2 | Execution price: 0=Next Open, 1=Next Close, 2=Current Close |
risk_control Format: "{stop_loss}/{take_profit}/{max_holding_days}". Empty values mean not set. Default "//21" = no stop/take-profit + 21-day forced exit. | string | "//21" | Stop-loss / Take-profit / Max holding days. See Risk Control |
| model | string | "cash" | Account model |
| exclude_oo | number | 0 | Exclude out-of-hours data |
| market_environment | number | 0 | Market environment filter |
| index_moving_average_slope | number | 0 | Index MA slope filter |
| opted | number | 0 | Optimization option |
| win_rate | string | "0.0000" | Win rate threshold (string) |
| backtest_period | string | â | Lookback period |
Frontend-Aligned Defaults
The API auto-fills all missing parameters via _apply_default_params(). Only override when you explicitly need different values.
POST /backtest/validate to preview the merged result without submitting a backtest. The response shows user_supplied (what you passed) vs defaults_applied (what the API filled in) side-by-side.// POST /backtest/validate â no Redis/RabbitMQ overhead // Request: same body as /backtest/start_backtest curl /backtest/validate \ -H "Content-Type: application/json" \ -d '{ "symbol": "SPY", "entry": {...}, "exit": {...} }' // Response â two columns: what you passed vs what was auto-filled { "status": "valid", "user_supplied": { "symbol": "SPY", "name": "Short Term Combined Model Strategy", "entry": { "rule_type": "SingleCondition", "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": { "extreme_optimism": "10", "extreme_pessimism": "-10" } }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }, "exit": { "rule_type": "SingleCondition", "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": { "extreme_optimism": "10", "extreme_pessimism": "-10" } }, "rule": { "comparison_type": "SV", "type_name": ">", "comparison_value": "13.5" } } } }, "defaults_applied": { "benchmark": "SPX", "capital": 100000, "capital_alloc": "1.000000", "commission": "0.0000", "slippage": "0.0000", "direction": "Long", "frequency": "Daily", "model": "cash", "strategy": "Single", "start_date": "1800-10-01", "trade_price": 2, "risk_control": "//21", "exclude_oo": 0, "market_environment": 0, "index_moving_average_slope": 0, "opted": 0, "win_rate": "0.0000" }, "entry": { "rule_type": "SingleCondition", "signals": [ { "code": "SI:Short Term Combined Model=extreme_optimism=10--extreme_pessimism=-10;SC:SV/2/-10", "signal_name": "Short Term Combined Model" } ] }, "exit": { "rule_type": "SingleCondition", "signals": [ { "code": "SI:Short Term Combined Model=extreme_optimism=10--extreme_pessimism=-10;SC:SV/0/13.5", "signal_name": "Short Term Combined Model" } ] } }
| Parameter | Frontend Default | Notes |
|---|---|---|
| benchmark | "SPX" | Performance benchmark |
| capital | 100000 | Initial capital |
| capital_alloc | "1.000000" | 100% per trade |
| commission | "0.0000" | Zero commission (string) |
| slippage | "0.0000" | Zero slippage (string) |
| direction | "Long" | Trade direction |
| frequency | "Daily" | Data frequency |
| model | "cash" | Account model |
| strategy | "Single" | Strategy type |
| start_date | "1800-10-01" | Max historical range |
| trade_price | 2 | 0=Next Open, 1=Next Close, 2=Current Close |
| risk_control | "//21" | No stop/take-profit, 21-day forced exit |
| exclude_oo | 0 | No overnight exclusion |
| market_environment | 0 | No market filter |
| index_moving_average_slope | 0 | No index filter |
| opted | 0 | No optimization |
| win_rate | "0.0000" | No win-rate filter (string) |
Rule Definition (entry / exit)
Both entry and exit share the same structure.
// Rule block structure { "rule_type": "SingleCondition | Scoring | TimeOrder | RiskControlOnly", "delay_bars": 0, "condition": { "signal": { ... }, "rule": { ... }, "qualifier": { ... } // optional } }
// SingleCondition example { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": {"extreme_optimism":"10","extreme_pessimism":"-10"} }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }
// RuleBlock schema type RuleBlock = { rule_type: string // "SingleCondition" | "Scoring" | "TimeOrder" | "RiskControlOnly" delay_bars: number // wait N bars after condition (default: 0) condition: { signal: Signal // { type, name, params? } rule: Rule // { comparison_type, type_name, comparison_value } qualifier: Qualifier? // optional secondary filter } }
| Field | Type | Description | Example |
|---|---|---|---|
delay_bars Number of bars to wait after condition is met before executing the trade. 0 = execute on the same bar the signal fires. 1 = wait one bar then execute. | int | Wait N bars after condition met. 0=same bar, 1=next bar | 0 |
Rule Types
condition is an array of {signal, rule} objects. Trigger when score_threshold of them are satisfied.steps). signals_in_market controls max interval. Default: 100000 (no limit).risk_control.entry.condition = single {signal, rule} objectScoring:
entry.condition = array of [{signal, rule}, ...] + score_thresholdTimeOrder:
entry.steps = array of [{signal, rule}, ...] + signals_in_market (NOT under condition!)
100000 = no interval limit. Set e.g. 21 to require all steps within 21 bars.cond[0]: Copies first step's qualifier (NOT default
{3,21,S}).SI:Smart Money Confidence;IDS:EO0.7/EP0.3;SC:SV/0/999999EO=
0.7, EP=0.3, value=999999, condition=> (code 0).Signal Definition
Define what data source drives the condition. Signal types are auto-detected.
all_indicators.csv (6284 indicators) â Sentiment (SI)2. Name in
ids_technical_name_map.json â Technical (TI)3. Otherwise â Symbol (SY)
You don't need to specify
signal.type â the API detects it automatically.all_indicators.csv. EO/EP must be set per indicator â defaults are rarely correct.Per indicatorExample:
"Short Term Combined Model""Symbol {Column}". Never include ticker in name.0/0Example:
"Symbol Close"ids_technical_name_map.json. URL/IDS auto-filled from map.20/80Example:
"Relative Strength Index""Symbol Close" â correctâ
"SPY Close" â wrong (ticker goes in top-level symbol param)â
"XBTUSD Close" â wrongColumn â {Open, High, Low, Close, Volume}
"Small Cap / S&P 500 Relative Ratio Rank" â "Ratio Rank" is part of the indicator name, NOT a qualifier. Do NOT add a Range Rank qualifier for this indicator.Rule Conditions
| Field | Type | Description | Example |
|---|---|---|---|
comparison_type The baseline for comparison. SV = raw signal value. SVMA/SVEMA = compare against a moving average of the signal. MA = only for Technical indicators with Moving Average type. | string | Comparison baseline: "SV" (value), "SVMA" (SMA), "SVEMA" (EMA), "MA" (Technical MA only) | "SV" |
| type_name | string | Comparison operator. See Condition Codes | "<", "CrossAbove" |
| comparison_value | string|number | Threshold value | "-10", 95 |
| period | string | MA period (required for SVMA/SVEMA) | "21" |
"SVMA" or "SVEMA" as comparison_type automatically generates a qualifier with the specified period and MA type. No need to add a manual qualifier in this case.Qualifier â Advanced Calculations
Optional secondary filter on the same indicator. Fires only when both main condition AND qualifier are true.
// Qualifier object { "comparison_operator": "Range Rank", "calculation_period": "21", "ma_type": "S" // "S" = SMA, "E" = EMA }
"Technical" signal type with a qualifier raises a ValueError. Use qualifiers only with Sentiment and Symbol signals.Condition Codes
16 operators mapped from type_name string to numeric code.
CrossBelow (code 4) is a crossing event â signal crosses below the threshold.< (code 2) is a static comparison â signal is below the threshold.These produce very different trade counts. Never substitute.
Qualifier Abbreviations
| Abbr | Full Name | Code | Typical Periods |
|---|---|---|---|
| OPR | % of Previous Range | 6 | 10, 20 |
| RR | Range Rank | 8 | 21, 84, 252 |
| DD | DrawDown % | 9 | 21, 252 |
| DU | DrawUp % | 10 | 21, 252 |
| ROC | Rate Of Change | 5 | 5, 10, 21 |
| MAR | MA Ratio | 7 | 21 |
| NC | Net Change | 11 | 1, 5 |
Risk Control Format
Format: "{stop_loss}/{take_profit}/{max_holding_days}"
Separator: / (empty = not set)
| Value | Stop-Loss | Take-Profit | Max Holding | Description |
|---|---|---|---|---|
| "//21" | â | â | 21 days | No stop/take-profit, 21-day forced exit (default) |
| "-5/10/21" | -5% | +10% | 21 days | Stop-loss -5%, take-profit 10% |
| "//" | â | â | â | No risk control at all |
Signal Encoding (Internal)
API auto-encodes user-friendly JSON into internal format. You never need to build this manually.
| Segment | Meaning | Example |
|---|---|---|
| SI / SY / TI | Signal type prefix | SI / SY / TI |
| IDS:EO/EP | Extreme optimism/pessimism | IDS:EO50/EP30 |
| SC:comp/code/val | Signal condition | SC:SV/2/15 (SV < 15) |
Encoding Examples
// Sentiment: Short Term Combined Model < -10 SI:Short Term Combined Model;IDS:EO10/EP-10;SC:SV/2/-10 // Symbol: Symbol Close CrossAbove MA SY:Symbol Close;IDS:EO0/EP0;SC:SVMA/3/21 // Technical: RSI < 30 TI:Relative Strength Index;IDS:EO20/EP80;SC:SV/2/30 // RiskControlOnly exit dummy SI:Smart Money Confidence;IDS:EO0.7/EP0.3;SC:SV/0/999999
API Response
Three endpoints handle the full lifecycle: submit a backtest, poll for results, and list past tasks.
Submit Backtest
{
"message": "Backtest task created successfully",
"task_id": "uuid"
}400 means required fields or strategy structure are invalid. 503 means Redis is unavailable and the task was not queued. 500 can occur when RabbitMQ delivery or CSV generation fails.Check Status
{
"status": "PENDING",
"params": { "symbol": "SPY", "...": "..." },
"username": "user@example.com",
"created_at": "2026-06-08T12:00:00"
}// SUCCESS â backtest finished, result contains metrics and trade dates { "status": "SUCCESS", "result": { "Symbol": "SPY", "Frequency": "Daily", "Total Trades": 44, "Total Positive": 40, "Total Negative": 4, "Win Rate": 90.91, "Average Win %": 3.72, "Average Loss %": -8.99, "Each Return": [11.72, 3.56, /* ...per trade */], "Total Return (%)": 184.85, "BuyHoldGain": 1578.54, "CAGR": 3.19, "Sharpe Ratio": 0.25, "Max Drawdown": 55.09, "DrawDown Period": 5123, "Time in Market": 32.15, "EntryDate": ["1997-07-18", /* ... */], "ExitDate": ["1998-02-13", /* ... */], "Last Entry Date": "2026-03-06", "Last Exit Date": "2026-05-15", "BT End Date": "2026-06-05" }, "params": { "symbol": "SPY", "...": "..." }, "username": "user@example.com", "created_at": "2026-06-08T12:00:00" }
List Tasks
{
"tasks": [
{
"task_id": "a3f8c1d2-7b4e-4f6a-9c8d-1e2f3a4b5c6d",
"status": "SUCCESS",
"strategy_name": "",
"symbol": "SPY",
"frequency": "Daily",
"created_at": "2026-06-05T12:00:00"
}
],
"total": 5,
"limit": 20,
"offset": 0
}Indicators List
Returns all available backtest indicators/signals from the SentimenTrader indicator database (22k+ entries). Can be filtered by name, type, or market symbol.
Endpoint
Response Fields
| Field | Type | Description |
|---|---|---|
chart_name | string | Display name of the indicator |
url | string | Internal indicator code used as indicator param in signal definitions |
market_symbol | string | Associated market symbol (e.g. SPX, SPY, COMP) |
type | string | Indicator type: optix, trend, reltrend, other |
updated | string | Update frequency: Daily, Weekly, Monthly |
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
q | string | No | Search indicator name (case-insensitive, partial match) |
type | string | No | Filter by indicator type (optix / trend / reltrend / other) |
symbol | string | No | Filter by market symbol (e.g. SPX, SPY) |
Response Example
[
{
"chart_name": "Macro Index Model",
"url": "macro_index_model",
"market_symbol": "SPX",
"type": "other",
"updated": "Monthly"
},
{
"chart_name": "SPY Optix",
"url": "etf_spy",
"market_symbol": "SPY",
"type": "optix",
"updated": "Daily"
}
]
?q=, ?type=, or ?symbol= to narrow results. Combine params for precision: ?q=Macro&type=other.cURL Examples
# Search by indicator name curl -u user:pass "https://st-tools.sentimentrader.com/backtest/indicators/list?q=Macro+Index+Model" # Filter by type curl -u user:pass "https://st-tools.sentimentrader.com/backtest/indicators/list?type=optix" # Filter by market symbol curl -u user:pass "https://st-tools.sentimentrader.com/backtest/indicators/list?symbol=SPX"
Indicator Metadata
Returns detailed metadata for a specific backtest indicator, including description, sentiment level, extreme thresholds, and chart configuration.
Endpoint
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
indicator | string | Yes | Indicator code from url field in /indicators/list (e.g. model_smart_dumb_spread) |
Response Fields
| Field | Type | Description |
|---|---|---|
sentiment | string | Sentiment level (0â4) |
description | string | Detailed HTML description of the indicator |
opt_extreme | float | Optimism extreme threshold |
pess_extreme | float | Pessimism extreme threshold |
contrary | string | Contrary indicator flag ("1.0" or "0") |
premium | string | Premium indicator flag ("0" or "1") |
chart_type | string | Chart render type (e.g. "line") |
updated | string | Update frequency |
frequency parameter must match the indicator's updated field. If they differ, validation passes but the backtest silently produces empty results. Example: Macro Index Model has "Monthly" â use "frequency": "Monthly", not "Daily".Response Example
{
"model_smart_dumb_spread": {
"sentiment": "4",
"description": "The Smart Money Confidence and Dumb Money Confidence...",
"opt_extreme": -0.25,
"pess_extreme": 0.25,
"contrary": "1.0",
"premium": "0",
"chart_type": "line",
"updated": "Daily"
}
}
cURL Example
curl -u user:pass "https://st-tools.sentimentrader.com/backtest/indicators/metadata?indicator=model_smart_dumb_spread"
CSV Mode
Use CSV mode when your frontend already has prepared OHLCV and signal rows. The API skips internal CSV generation, validates the rows, stores the CSV payload, and queues the task.
{
"symbol": "SPY",
"csv_mode": true,
"csv_data": [
{ "Date": "2024-01-02", "Open": 470, "High": 472.5, "Low": 469, "Close": 471.5, "Volume": 1000 }
],
"entry": {
"rule_type": "SingleCondition",
"condition": {
"signal": { "type": "Symbol", "name": "Symbol Close" },
"rule": { "comparison_type": "SV", "type_name": ">", "comparison_value": "0" }
}
},
"exit": { "rule_type": "RiskControlOnly" }
}
| Field | Requirement |
|---|---|
csv_data | Required when csv_mode is true; must be an array of row objects |
| Required columns | Date, Open, High, Low, Close, Volume |
| Signal columns | Entry1-Entry5 and Exit1-Exit5 are optional; missing columns are filled with 0 |
| Extra columns | Dropped before queueing; the worker receives the standard 16-column shape |
Complete Workflow
The three-step cycle for every backtest: validate encoding, submit job, poll for results.
Step 1: Validate
Always validate before submitting. Returns encoded signals so you can verify the API interpreted your params correctly. No Redis/RabbitMQ overhead.
Request body is identical to submit. Response shows encoded signals:
{
"status": "valid",
"entry": {
"signals": [{"code": "SI:Macro Index Model;IDS:EO0.7/EP0.7;SC:SV/3/0.7"}],
"cond": [{"newCondition": 3, "conditionPeriod": "21", "ma_type": "S"}]
},
"exit": {
"signals": [{"code": "SI:Macro Index Model;IDS:EO0.7/EP0.7;SC:SV/4/0.7"}],
"cond": [{"newCondition": 4, "conditionPeriod": "21", "ma_type": "S"}]
},
"warnings": []
}Step 2: Submit
After confirming encoding, submit to start the backtest. Returns a task_id for polling.
{
"message": "Backtest task created successfully",
"task_id": "a3f8c1d2-7b4e-4f6a-9c8d-1e2f3a4b5c6d"
}Step 3: Poll
Poll every 10â15 seconds until status is SUCCESS or FAILED. Typical backtests complete in 10â60 seconds. TimeOrder SPX Daily (~25K bars) may take up to 90s.
| Status | Meaning | Action |
|---|---|---|
PENDING | Queued | Poll in 10â15s |
RUNNING | Processing | Poll in 10â15s |
SUCCESS | Complete | Parse result |
FAILED | Error | Check result |
Troubleshooting
Common issues and how to diagnose them.
| Symptom | Likely Cause | Fix |
|---|---|---|
| 0 trades | Frequency mismatch â indicator is Monthly but frequency: "Daily" |
Match frequency to indicator's updated field |
| 0 trades (pre-1990) | Volume column was 0, worker treated as suspended | Fixed (Volume floor = 1) |
| Validate or submit returns 400 | Scoring condition is a single object instead of an array, or required fields are missing |
Use "condition": [{...}, {...}] (array) |
| TimeOrder returns 400 | Conditions wrapped in "condition": {"steps": [...]} |
Use "steps": [...] directly at entry/exit level |
| Fewer trades than expected | risk_control: "//21" forces exit too early |
Use "//" when exit has explicit signals |
Duplicate frequency key in JSON |
Last value wins â e.g. "Monthly" then "Daily" â "Daily" used |
Check JSON for accidental duplicates |
Full Examples
// Minimal â only 3 fields, 12 params auto-filled // This is all you need. Everything else gets sensible defaults. { "symbol": "SPY", "entry": { "rule_type": "SingleCondition", "condition": { "signal": { "name": "Short Term Combined Model" }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }, "exit": { "rule_type": "RiskControlOnly" } } // â 202 Accepted { "message": "Backtest task created successfully", "task_id": "a3f8..." } // Auto-filled: benchmark="SPX", capital=100000, direction="Long", // frequency="Daily", trade_price=2, risk_control="//21" âĻ +7 more
// SingleCondition â Sentiment < -10 entry, > 13.5 exit // Minimal: only symbol + entry + exit required; all other params auto-filled { "symbol": "SPY", "name": "Short Term Combined Model Strategy", "benchmark": "SPX", "direction": "Long", "frequency": "Daily", "capital": 100000, "capital_alloc": "1.000000", "trade_price": 2, "risk_control": "//21", "entry": { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": {"extreme_optimism":"10","extreme_pessimism":"-10"} }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } } }, "exit": { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": {"extreme_optimism":"10","extreme_pessimism":"-10"} }, "rule": { "comparison_type": "SV", "type_name": ">", "comparison_value": "13.5" } } } }
// SingleCondition with Range Rank qualifier â delay 1 bar { "symbol": "SPY", "name": "Smart Money Confidence Spread Strategy", "benchmark": "SPX", "direction": "Long", "frequency": "Daily", "capital": 100000, "capital_alloc": "1.000000", "trade_price": 2, "risk_control": "//21", "entry": { "rule_type": "SingleCondition", "delay_bars": 1, "condition": { "signal": { "type": "Sentiment", "name": "Smart Money / Dumb Money Confidence Spread" }, "rule": { "comparison_type": "SV", "type_name": "=", "comparison_value": "100", "qualifier": { "comparison_operator": "Range Rank", "calculation_period": "21", "ma_type": "S" } } } }, "exit": { "rule_type": "SingleCondition", "delay_bars": 0, "condition": { "signal": { "type": "Sentiment", "name": "Smart Money / Dumb Money Confidence Spread" }, "rule": { "comparison_type": "SV", "type_name": ">=", "comparison_value": "-100" } } } }
// TimeOrder â Multi-step entry with 21-bar forced exit { "symbol": "SPY", "name": "Small Cap Relative Ratio Strategy", "benchmark": "SPX", "direction": "Long", "frequency": "Daily", "capital": 100000, "capital_alloc": "1.000000", "trade_price": 2, "risk_control": "//21", "entry": { "rule_type": "TimeOrder", "signals_in_market": 100000, "steps": [ { "signal": { "name": "Small Cap / S&P 500 Relative Ratio Rank" }, "rule": { "comparison_type":"SV", "type_name":"CrossAbove", "comparison_value":"95" } }, { "signal": { "name": "Small Cap / S&P 500 Relative Ratio Rank" }, "rule": { "comparison_type":"SV", "type_name":"CrossBelow", "comparison_value":"15" } } ] }, "exit": { "rule_type": "RiskControlOnly" } }
// Scoring â 2 of 3 voters must be true to trigger entry { "symbol": "SPY", "name": "Multi-Signal Voting Strategy", "benchmark": "SPX", "direction": "Long", "frequency": "Daily", "capital": 100000, "capital_alloc": "1.000000", "trade_price": 2, "risk_control": "//21", "entry": { "rule_type": "Scoring", "score_threshold": 2, "voters": [ { "signal": { "type": "Sentiment", "name": "Short Term Combined Model", "params": {"extreme_optimism":"10","extreme_pessimism":"-10"} }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-10" } }, { "signal": { "type": "Sentiment", "name": "Smart Money / Dumb Money Confidence Spread" }, "rule": { "comparison_type": "SV", "type_name": "<", "comparison_value": "-30" } }, { "signal": { "type": "Sentiment", "name": "Small Cap / S&P 500 Relative Ratio Rank" }, "rule": { "comparison_type": "SV", "type_name": ">", "comparison_value": "80" } } ] }, "exit": { "rule_type": "RiskControlOnly" } } // score_threshold=2: at least 2 of the 3 voters must be true // Each voter is a complete condition (signal + rule)