Documentation
How to read and edit the Python file QuantifyMe writes for a strategy, and how to drive the whole platform over HTTP. One call takes a sentence to a live model.
Start here
Get an API key
Every authenticated call sends an X-API-Key header. A trial key needs no account and no email: it is temporary, carries 10,000 credits and is kept in this browser. Sign in for a permanent personal key.
qm_b4••••••••••••••••••••••4ac5
No account needed. One click makes a temporary key.
A script or an agent mints its own key the same way, with one request and no body.
curl -X POST https://api.quantifyme.ai/api/v1/key/trial # {"api_key": "qm_...", "username": "trial_...", "is_trial": true}
Deploy from one sentence
Describe a strategy in one line. QuantifyMe writes the code, trains a model on recent prices, and deploys it live. It usually takes under a minute.
The four steps the server reports. Usually under a minute.
Stop only stops watching. The run finishes on the server and its model appears in your Backtesting list.
Training and validation
| Training | Validation |
|---|
- A market named in the sentence wins. "EURUSD 1min RSI reversal" moves the two pickers to EURUSD and 1 min before the run starts, so you can see what is about to train.
- How much history a run trains on depends on the timeframe. On a free or trial key it is the last 40 days at 15 min and 1 h, 18 days at 5 min and 4 days at 1 min.
- A link can fill the box:
/docs?prompt=Buy+when+RSI+hits+30#quick-deploy. Addrun=1and the deploy starts by itself, which is how an AI assistant hands a strategy over in one click.
The same request over the API
This is what ChatGPT, Claude or your own script sends. The sample follows what you type above and the market you pick.
POST https://api.quantifyme.ai/api/v1/one_shot X-API-Key: qm_YOUR_KEY Content-Type: application/json { "prompt": "Buy when RSI hits 30, sell when RSI hits 70", "symbol": "EURUSD", "timeframe": "15min", "deliver_to": { "webhook": "https://example.com/hook" } }
curl -N -X POST https://api.quantifyme.ai/api/v1/one_shot \ -H 'X-API-Key: qm_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{"prompt":"Buy when RSI hits 30, sell when RSI hits 70","symbol":"EURUSD","timeframe":"15min","deliver_to":{"webhook":"https://example.com/hook"}}'
import os, sys, json, webbrowser, requests API_KEY = os.environ.get("QUANTIFYME_API_KEY", "qm_YOUR_KEY") with requests.post( "https://api.quantifyme.ai/api/v1/one_shot", headers={"X-API-Key": API_KEY}, json={"prompt": "Buy when RSI hits 30, sell when RSI hits 70", "symbol": "EURUSD", "timeframe": "15min", "deliver_to": {"webhook": "https://example.com/hook"}}, stream=True, timeout=600, ) as resp: event = None for line in resp.iter_lines(decode_unicode=True): if not line: continue if line.startswith("event:"): event = line.split(":", 1)[1].strip() elif line.startswith("data:"): data = json.loads(line.split(":", 1)[1]) if event == "token": sys.stdout.write(data["text"]); sys.stdout.flush() elif event == "step": print(f'\n[{data["pct"]:>3}%] {data["stage"]}: {data.get("msg", "")}') elif event == "done": print("\nLIVE:", data["live_url"]) webbrowser.open(data["live_url"]) break elif event == "error": raise RuntimeError(data["error"])
const res = await fetch("https://api.quantifyme.ai/api/v1/one_shot", { method: "POST", headers: { "X-API-Key": "qm_YOUR_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ prompt: "Buy when RSI hits 30, sell when RSI hits 70", symbol: "EURUSD", timeframe: "15min", deliver_to: { webhook: "https://example.com/hook" }, }), }); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buf = "", event = null; while (true) { const { value, done } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); const lines = buf.split("\n"); buf = lines.pop(); for (const line of lines) { if (line.startsWith("event:")) event = line.slice(6).trim(); else if (line.startsWith("data:")) { const data = JSON.parse(line.slice(5)); if (event === "token") process.stdout.write(data.text); else if (event === "step") console.log(`\n[${data.pct}%] ${data.stage}: ${data.msg||""}`); else if (event === "done") { console.log(`\nLIVE: ${data.live_url}`); return; } else if (event === "error") throw new Error(data.error); } } }
The response is a stream of server-sent events. Field by field: POST /api/v1/one_shot.
For AI agents
/llms.txt is a plain-text version of this documentation written for AI assistants such as ChatGPT, Claude and Gemini. Paste the URL into any AI chat and it can help you write or change your strategy code: it already knows the signal convention, the file structure and the common patterns.
It follows the llms.txt standard, a plain-text file at the root of the domain that an assistant can read. The same contract is published in two more machine-readable forms.
| File | What it is |
|---|---|
/llms.txt | This documentation as plain text, at quantifyme.ai/llms.txt |
/openapi.json | The full catalogue of paths, as OpenAPI |
/api/v1/docs | The core endpoints as JSON, with examples |
Strategy code
Every strategy QuantifyMe generates is one self-contained Python file. This part explains how to read it, what each section does, and how to make the common edits, with a map for anyone coming from PineScript.
How it works
A generated strategy file has exactly two functions: feature_engineering() and strategy_config(). You describe the strategy through those two, and the framework does everything else. It builds and trains the model, turns its probabilities into buy, sell and flat signals, applies your position, session and trend filters, runs the walk-forward backtest with your stop loss, take profit and cooldown, and computes every metric.
There is no build_model, generate_signals, apply_risk or train_and_backtest to edit any more. Older docs that mention "7 numbered sections" describe the framework before 2026.
| You write | What it does |
|---|---|
feature_engineering(df, close, open_, high, low) | Add indicator and pattern columns to df and return it. Every new column becomes an ML feature. No look-ahead, end with .bfill().ffill(), and do not drop rows. |
strategy_config(), returns a dict | One dict: model_type and model_params, signal_threshold, direction, stop_loss, take_profit, cooldown, max_positions, on_opposite, session_filter, min_atr, trend_filter, target_horizon, plus title, objective and notes. |
Backtest basics. Walk-forward, with no look-ahead. Entry is on the next bar's open after a signal. Stop loss and take profit are checked inside the bar against its high and low. Commission is charged on every position change. Data is forex OHLC for any of 7 majors (EUR/USD, GBP/USD, USD/JPY, USD/CHF, AUD/USD, NZD/USD, USD/CAD) at 1 min, 5 min, 15 min and 1 h. Pick it with the symbol and timeframe fields.
The strategy file
The whole file is two functions and a small header. You add features in the first function and set the knobs in the second.
# SECTION 0 - IMPORTS AND CONSTANTS (do not change these) import numpy as np import pandas as pd DATA_PATH = "..."; START_DATE = "..."; END_DATE = "..."; VALIDATION_DATE = ""; TRAIN_SPLIT = 0.7 # SECTION 1 - FEATURE ENGINEERING (add columns here; each one becomes an ML feature) def feature_engineering(df, close, open_, high, low): df['rsi_14'] = _rsi(close, 14) df['ema_20'] = close.ewm(span=20, adjust=False).mean() df['ema_50'] = close.ewm(span=50, adjust=False).mean() df['ret_1'] = close.pct_change() df = df.bfill().ffill() # fill indicator warm-up NaNs: required return df # SECTION 2 - STRATEGY CONFIG (every key required) def strategy_config(): return { "model_type": "XGBClassifier", "model_params": {"n_estimators": 300, "max_depth": 4, "learning_rate": 0.05}, "signal_threshold": 0.55, # predict_proba cutoff for a signal "direction": "both", # "both" | "long" | "short" "stop_loss": 0.005, # 0.5%, a decimal ratio, or None "take_profit": 0.01, # 1.0%, a decimal ratio, or None "cooldown": 0, # bars to wait after a close before re-entry "max_positions": 1, "on_opposite": "reverse", # "reverse" (flip) | "close_only" (go flat) "session_filter": None, # [start_hour, end_hour] UTC, e.g. [7, 16] "min_atr": None, # minimum NATR to allow entries "trend_filter": None, # e.g. "sma_50": longs above, shorts below "target_horizon": 4, # bars ahead the model predicts (4 is about 1 h on 15 min) "title": "EUR/USD Momentum (RSI+EMA, XGBoost)", "objective": "capture intraday momentum continuation", "notes": "shallow trees + low LR for noisy FX", }
What you do not write. No build_model, generate_signals, apply_risk, train_and_backtest, or any backtest or metric code. The framework loads the OHLC, calls your feature_engineering(), strips the warm-up rows, builds the target (sign(close.shift(-target_horizon) - close)), splits train and test, fits the model, thresholds predict_proba to -1, 0 or 1, applies your filters, runs the backtest with your stop loss, take profit and cooldown, and returns all the metrics.
Common edits
All of these are one key in strategy_config().
| Goal | Change |
|---|---|
| Long only, or short only | direction = "long" or "short" |
| Add or change the stop loss and take profit | stop_loss = 0.005 (0.5%), take_profit = 0.01 (1.0%). Decimal ratios: on EUR/USD 0.005 is about 50 pips. None turns one off. |
| Trade less oftenA stricter cutoff, which is a different thing from a more reliable one | Raise signal_threshold (0.60 to 0.70), set cooldown above 0, or both |
| Trade more often | Lower signal_threshold toward 0.50 |
| Trade only in a session, in UTC hours | session_filter = [7, 16] (London), [13, 17] (London and New York overlap), [0, 9] (Tokyo) |
| Skip dead, low-volatility periods | min_atr = 0.0003 (the minimum NATR) |
| Trade only with the trend | trend_filter = "sma_50" |
| Predict further or nearer ahead | target_horizon = N. On 15 min bars, 1 is the next bar, 4 is about 1 h and 16 is about 4 h. |
| Reverse, or go flat, on the opposite signal | on_opposite = "reverse" or "close_only" |
| Use a different model | model_type: XGBClassifier, RandomForestClassifier, GradientBoostingClassifier, ExtraTreesClassifier or LogisticRegression, with matching model_params |
| Add an indicator or a candle pattern | Add the column inside feature_engineering() and the model learns it. See Add an indicator. |
Add an indicator
Put it in feature_engineering(). Every new column on df becomes an ML feature by itself. No look-ahead, which means no negative shifts. Do not drop rows, and finish with .bfill().ffill().
def feature_engineering(df, close, open_, high, low): # MACD ema12 = close.ewm(span=12).mean(); ema26 = close.ewm(span=26).mean() df['macd'] = ema12 - ema26 df['macd_sig'] = df['macd'].ewm(span=9).mean() df['macd_hist'] = df['macd'] - df['macd_sig'] # Bollinger position mid = close.rolling(20).mean(); sd = close.rolling(20).std() df['bb_pos'] = (close - (mid - 2*sd)) / ((mid + 2*sd) - (mid - 2*sd) + 1e-9) # ATR / NATR (for volatility context) tr = pd.concat([high-low, (high-close.shift(1)).abs(), (low-close.shift(1)).abs()], axis=1).max(axis=1) df['natr_14'] = tr.rolling(14).mean() / close # Candle pattern: hammer body = (close-open_).abs() lower_wick = pd.concat([close, open_], axis=1).min(axis=1) - low upper_wick = high - pd.concat([close, open_], axis=1).max(axis=1) df['hammer'] = ((lower_wick > 2*body) & (upper_wick < 0.3*body) & (close > open_)).astype(float) # Time of day (cyclical) df['hour_sin'] = np.sin(2*np.pi*df.index.hour/24) df['hour_cos'] = np.cos(2*np.pi*df.index.hour/24) return df.bfill().ffill()
For a custom indicator from Pine Script or plain English, POST /api/v1/indicators/custom writes the feature code for you. The full indicator catalogue is at GET /api/v1/indicator-schema.
PineScript and Python
There is no PineScript here: the generated code is Python. The logic is the same, with entries, exits, signals and indicators, and only the syntax differs. If you know PineScript, this is how the concepts map across.
| Concept | PineScript | Python |
|---|---|---|
| Go long | strategy.entry("L", strategy.long) | signal = 1 |
| Go short | strategy.entry("S", strategy.short) | signal = -1 |
| Close, or stay flat | strategy.close_all() | signal = 0 |
| Current close | close | close or ohlc['close'] |
| Previous close | close[1] | close.shift(1) |
| Current open | open | ohlc['open'] |
| The bar's high and low | high, low | ohlc['high'], ohlc['low'] |
| SMA(close, 20) | ta.sma(close, 20) | close.rolling(20).mean() |
| EMA(close, 20) | ta.ema(close, 20) | close.ewm(span=20).mean() |
| RSI(close, 14) | ta.rsi(close, 14) | See Add an indicator |
| Crossover(fast, slow) | ta.crossover(fast, slow) | (fast > slow) & (fast.shift(1) <= slow.shift(1)) |
| Bar index | bar_index | df.index (a datetime) |
| Day of week | dayofweek | df.index.dayofweek (0 is Monday, 4 is Friday) |
| Hour of day | hour | df.index.hour |
| Minute | minute | df.index.minute |
API reference
Overview and auth
All endpoints live under /api/v1/. Authenticated endpoints need an X-API-Key header.
# Base URL https://api.quantifyme.ai/api/v1/ # Auth header X-API-Key: qm_xxxxxxxxxxxxxxxx
Signed in, this copies your personal key. Otherwise it makes a trial key. It is the same key as in Get an API key.
Quick start. The Full example is one script you can copy and run that covers generate, train and results.
POST /api/v1/one_shot
One streamed call from a sentence to a live model: it writes the strategy, trains and backtests it, deploys it, and shares it to the community. Deploy from one sentence shows the request as raw HTTP, curl, Python and Node.js.
| Body field | Meaning |
|---|---|
prompt | The strategy in plain English. A vague request deploys the best curated preset for the market, or writes a new strategy when there is none, and a specific rule writes a new one. A community strategy deploys only when you name it with community_id. |
symbol, timeframe | The market to train on, for example "EURUSD" and "15min". A market named in the prompt wins. |
code | Your own strategy code. Generation is skipped. |
preset, community_id | Deploy a preset, or a strategy from the community, in place of a prompt |
claude_model | "sonnet" or "haiku", the model that writes the strategy |
start_date, end_date | Optional. Left out, the server picks the default window. |
deliver_to | Where live signals go: Telegram, Email, Discord or Webhook. A channel counts only when it carries its address, so send the URL itself as "webhook". With no address the model still goes live, with no delivery set up. |
The stream
Four event names arrive: token carries the strategy code as it is written, step reports progress, done closes a good run and error closes a failed one. A step names one of four stages, in this order.
| Stage | What is happening |
|---|---|
generate | Writing the strategy |
train | Training and backtesting the model |
deploy | Deploying it |
share | Sharing it to the community, when the result qualifies |
event: step data: {"stage": "generate", "pct": 10, "msg": "..."} event: token data: {"text": "def feature_engineering("} event: step data: {"stage": "train", "pct": 60, "msg": "..."} event: step data: {"stage": "deploy", "pct": 85, "msg": "Deploying model..."} event: step data: {"stage": "share", "pct": 97, "msg": "Auto-shared to /community ..."} event: done data: {"live_url": "...", "model": "...", "stem": "...", "channels": [], "start_date": "...", "end_date": "...", "source": "generated", "train_stats": {"trades": 0, "win_rate": 0, "profit_factor": 0, "return": 0, "sharpe": 0, "max_drawdown": 0}}
The done event carries live_url, model, stem, channels, the start_date and end_date that were really trained, source ("generated", "preset" or "community") and train_stats. A community deploy adds author and community_id.
POST /api/v1/generate
Generate a full Python strategy from plain English. Each field takes a free-text description: features, signals, model, optimization, risk and risk_function. Pass structured indicators as well when you want exact parameters.
import requests resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "MACD histogram slope, RSI divergence", "signals": "Long when MACD crosses above zero with RSI confirmation", "model": "XGBoost", "optimization": "Maximize Sharpe ratio", "risk": "Stop loss 0.3%, scale by ATR", "risk_function": "Skip trades on Fridays after 18:00 UTC", "indicators": { "macd_enabled": True, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "rsi_enabled": True, "rsi_period": 14, "atr_enabled": True, "atr_period": 14, }, "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0}, "start_date": "2025-01-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet", }, headers={"X-API-Key": "qm_xxx"}) code = resp.json()["code"]
indicators is optional. When you send it, the model that writes the code receives exact parameters, for example "RSI with period=14", and does not have to parse free text. GET /api/v1/indicator-schema lists every indicator.
Options for pos_rules
| Field | Options | Default |
|---|---|---|
max_pos | 1, 2, 3 | 1 |
on_opposite | reverse, close_only, ignore | reverse |
direction | both, long, short | both |
cooldown | 0 to 100, in bars | 0 |
POST /api/v1/generate/from-template
Generate strategy code from a curated template. You can override any field: a text field replaces the template's, and a dict field (indicators, pos_rules) merges into it.
resp = requests.post("https://api.quantifyme.ai/api/v1/generate/from-template", json={ "template": "scalper", "start_date": "2025-01-01", "end_date": "2026-04-01", "pos_rules": {"direction": "long"}, # override: long only "indicators": {"rsi_period": 21}, # override: RSI 21 instead of 14 "claude_model": "sonnet", }, headers={"X-API-Key": "qm_xxx"})
Available templates
| Key | Name | Description |
|---|---|---|
macd_momentum | MACD Momentum | Trend following with MACD crossovers and RSI confirmation |
mean_reversion | Mean Reversion | Fade extremes with Bollinger Bands and RSI |
trend_following | Trend Following | EMA crossovers and ATR position sizing |
scalper | Scalper | High frequency with Stochastic and Bollinger Bands |
conservative_long | Conservative Long-Only | SMA trend and strict drawdown control |
POST /api/v1/indicators
Compute built-in indicators on OHLC data without training a model. The values come back as JSON.
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators", json={ "indicators": {"rsi_enabled": True, "rsi_period": 14, "macd_enabled": True}, "symbol": "EURUSD", "timeframe": "15min", "start": "2026-04-01", "limit": 100, "format": "columns", # or "rows" }, headers={"X-API-Key": "qm_xxx"}) data = resp.json() # data["ind_rsi14"] -> [45.2, 48.1, 52.3, ...] # data["timestamps"] -> ["2026-04-01 00:00:00", ...]
Available indicators
| Indicator | Params | Features |
|---|---|---|
| SMA | sma_periods = "20,50,200" | sma_{P}, dm_sma_{P} |
| EMA | ema_periods = "9,21,50" | ema_{P}, dm_ema_{P} |
| Bollinger Bands | bb_period = 20, bb_std = 2.0 | bb_width, bb_pct |
| RSI | rsi_period = 14 | rsi_{P} |
| MACD | macd_fast = 12, macd_slow = 26, macd_signal = 9 | macd_line, macd_hist |
| Stochastic | stoch_k = 14, stoch_d = 3 | stoch_k, stoch_d |
| ATR | atr_period = 14 | atr_{P}, natr_{P} |
WMA is in the schema too. Its parameters are in GET /api/v1/indicator-schema.
POST /api/v1/indicators/custom
Convert Pine Script or plain English into a computed indicator. It returns overlays, panels, signals and ML features.
# Natural language resp = requests.post("https://api.quantifyme.ai/api/v1/indicators/custom", json={ "source": "Supertrend indicator with ATR period 10 and multiplier 3", "timeframe": "15min", "fe_mode": "basic", # "full" | "basic" | "none" }, headers={"X-API-Key": "qm_xxx"}) # Pine Script resp = requests.post("https://api.quantifyme.ai/api/v1/indicators/custom", json={ "source": "//@version=5\nindicator('My RSI')\nplot(ta.rsi(close, 14))", "provider": "anthropic", # "anthropic" | "groq" | "ollama" }, headers={"X-API-Key": "qm_xxx"}) result = resp.json() # result["name"] -> "Supertrend" # result["overlays"] -> [{id, color, data}] # result["panels"] -> [{id, title, lines, h_lines}] # result["signals"] -> [{time, type: "buy"|"sell"}] # result["features"] -> {col_name: [{time, value}]}
Discovery
These endpoints are public and need no API key. Use them to find the available options before you call an authenticated endpoint.
| Endpoint | Returns |
|---|---|
GET /api/v1/indicator-schema | All 8 indicators with parameter names, types, defaults and the feature columns they generate |
GET /api/v1/presets | The chip presets the website uses, the pos_rules schema and the 5 strategy templates |
GET /api/v1/docs | Machine-readable JSON docs: the core endpoints, with examples. The full path catalogue is /openapi.json. |
GET /api/v1/examples | Every example in the Example library, with its full runnable code |
# Discover available indicators schema = requests.get("https://api.quantifyme.ai/api/v1/indicator-schema").json() # Discover templates + presets presets = requests.get("https://api.quantifyme.ai/api/v1/presets").json() # presets["templates"]["macd_momentum"]["config"] -> ready for /generate
Scripts and tools
Full example
One script from start to finish: generate a strategy, train the model, poll until it is done, and print the results. Replace API_KEY with yours.
The same key as in Get an API key.
# QuantifyMe API - Full Example # 1. Generate strategy code from natural language # 2. Submit for training # 3. Poll until complete # 4. View results import requests, time # CONFIG: paste your API key here BASE = "https://api.quantifyme.ai" API_KEY = "qm_PASTE_YOUR_KEY_HERE" # from "Get an API key" on this page HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"} # STEP 1: Generate strategy code print("Generating strategy...") resp = requests.post(f"{BASE}/api/v1/generate", json={ # Natural language: describe your strategy "features": "MACD (12,26,9), RSI 14, ATR 14, Volume Z-score", "signals": "Buy when MACD crosses above zero and RSI < 60", "model": "XGBoost", "optimization": "Maximize Sharpe ratio, keep max drawdown under 15%", "risk": "Stop loss 0.3%, fixed 1% risk per trade", # Structured indicators: exact params (optional, overrides NL) "indicators": { "macd_enabled": True, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "rsi_enabled": True, "rsi_period": 14, "atr_enabled": True, "atr_period": 14, }, # Position rules "pos_rules": { "max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0, }, # Date range + model "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet", }, headers=HEADERS) code = resp.json()["code"] print(f"Strategy generated ({len(code)} chars)") # STEP 2: Submit for training print("Submitting for training...") resp = requests.post(f"{BASE}/api/v1/train", json={ "code": code, "model_name": "API Test Model", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "timeframe": "15min", }, headers=HEADERS) job = resp.json() job_id = job["job_id"] print(f"Job {job_id} queued") # STEP 3: Poll until done while True: resp = requests.get(f"{BASE}/api/v1/train/{job_id}", headers=HEADERS) status = resp.json() print(f" Status: {status['status']}") if status["status"] in ("done", "failed"): break time.sleep(3) # STEP 4: View results if status["status"] == "done": m = status.get("metrics", {}) print("Training complete!") print(f" Return: {m.get('total_ret', 0):.2%}") print(f" Sharpe: {m.get('sharpe_strat', 0):.2f}") print(f" Drawdown: {m.get('mdd', 0):.2%}") print(f" Trades: {m.get('n_trades', 0)}") else: print(f"Training failed: {status.get('error', 'unknown')}") # BONUS: Use a template instead (no NL needed) # resp = requests.post(f"{BASE}/api/v1/generate/from-template", json={ # "template": "scalper", # "start_date": "2025-06-01", # "end_date": "2026-04-01", # "claude_model": "sonnet", # }, headers=HEADERS) # BONUS: Compute indicators without training # resp = requests.post(f"{BASE}/api/v1/indicators", json={ # "indicators": {"rsi_enabled": True, "macd_enabled": True}, # "timeframe": "15min", "limit": 100, # }, headers=HEADERS) # print(resp.json()["ind_rsi14"][:5]) # first 5 RSI values
How long it takes. About 10 to 30 seconds in all. Step 1, generation, takes about 5 seconds. Step 3, training, takes 5 to 15 seconds depending on how much data there is. The while True loop polls every 3 seconds until the job is done.
Command-line bot
If you would rather not write the HTTP layer, qm-bot-template is a Python command-line tool that wraps every endpoint on this page and uses only the standard library. It mints its own trial key, retries on transient errors and gives every failure its own exception type.
qmbot mint # trial key with 10,000 credits, cached qmbot one-shot "Buy when RSI<30 on EURUSD 15m" # generate, train, deploy qmbot fork --publish # fork the top of /community, retrain, republish if profitable qmbot watch --kind FORKED # live tail of every other bot's activity
What is in it
- Subcommands:
mint,whoami,one-shot,generate,train,forkandwatch. - Typed exceptions, so a wrapper can branch on how a call failed:
AuthError,RateLimitError(with.retry_after),BudgetErrorandNetworkError. - Automatic retry with exponential backoff. It honours
Retry-Afteron a 429 or a 503. - Typed exit codes for shell scripts: 2 is auth, 3 is a rate limit, 4 is budget, 5 is validation and 6 is network.
- No runtime dependencies. Python 3.9 or later. It runs on any VPS.
Build and run from this page
Put examples together into one strategy, then train it and deploy it without leaving the docs. Each block is also a script you can copy.
Build and test
Generate a strategy from the seven slots, train it, and see the backtest. The script below follows the slots as you fill them, and it is the same script you would run yourself.
- 1FeaturesEmpty
- 2SignalsEmpty
- 3ModelEmpty
- 4OptimisationEmpty
- 5RiskEmpty
- 6Position rulesEmpty
- 7FilterEmpty
import requests, time, json BASE = "https://api.quantifyme.ai" API_KEY = "qm_YOUR_KEY" # from "Get an API key" on this page H = {"X-API-Key": API_KEY, "Content-Type": "application/json"} # Step 1: Generate strategy code (streaming) # Tokens stream live as Claude writes the code body = { "features": "", "signals": "", "model": "", "optimization": "", "risk": "", "risk_function": "", "indicators": {}, "pos_rules": {}, # start_date/end_date are optional: omitted here so the server picks # the same default window /landing and Quick Deploy use "train_split": 0.7, "claude_model": "sonnet" } code = "" with requests.post(f"{BASE}/api/v1/generate/stream", json=body, headers=H, stream=True, timeout=120) as r: for line in r.iter_lines(): if line and line.startswith(b"data: "): d = json.loads(line[6:]) if d["type"] == "token": print(d["text"], end="", flush=True) # live streaming! code += d["text"] elif d["type"] == "done": code = d["code"] elif d["type"] == "error": print(f"Error: {d['error']}") print(f"Generated {len(code)} chars") if not code: raise RuntimeError("No code generated: check API key and credits") # Step 2: Train resp = requests.post(f"{BASE}/api/v1/train", json={ "code": code, "model_name": "My Strategy", # start_date/end_date are optional: omitted here so the server picks # the same default window /landing and Quick Deploy use "train_split": 0.7, "symbol": "EURUSD", "timeframe": "15min" }, headers=H).json() if "error" in resp: raise RuntimeError(resp["error"]) job_id = resp["job_id"] print(f"Job {job_id} submitted | model: {resp.get('model_name', 'My Strategy')}") # Step 3: Poll while True: s = requests.get(f"{BASE}/api/v1/train/{job_id}", headers=H).json() print(s["status"]) if s["status"] in ("done", "failed"): break time.sleep(3) # Step 4: Results if s["status"] == "done": tr = s.get("train_stats", {}) te = s.get("test_stats", {}) def p(v, w=13): return str(v).rjust(w) def pct(v): return f"{v*100:.2f}%" def pct4(v): return f"{v*100:.4f}%" def dol(v): return f"${v:+,.2f}" B = "│"; T = "─"; TL = "┌"; TR = "┐"; BL = "└"; BR = "┘" ML = "├"; MR = "┤"; TM = "┬"; BM = "┴"; X = "┼" top = f" {TL}{T*20}{TM}{T*14}{TM}{T*14}{TR}" mid = f" {ML}{T*20}{X}{T*14}{X}{T*14}{MR}" bot = f" {BL}{T*20}{BM}{T*14}{BM}{T*14}{BR}" row = lambda l, a, b: f" {B} {l:<18}{B}{p(a)} {B}{p(b)} {B}" print() print(top) print(f" {B}{' ':20}{B}{' TRAIN ':14}{B}{' TEST ':14}{B}") print(mid) print(row("Net Profit", dol(tr.get("np",0)), dol(te.get("np",0)))) print(row("Total Return", pct(tr.get("ret",0)), pct(te.get("ret",0)))) print(row("Profit Factor", f"{tr.get('pf',0):.2f}", f"{te.get('pf',0):.2f}")) print(row("Max Drawdown", pct(abs(tr.get("mdd",0))), pct(abs(te.get("mdd",0))))) print(mid) print(row("Total Trades", tr.get("n",0), te.get("n",0))) print(row("Winning Trades", tr.get("wins",0), te.get("wins",0))) print(row("Losing Trades", tr.get("losses",0), te.get("losses",0))) print(row("Win Rate", pct(tr.get("wr",0)), pct(te.get("wr",0)))) print(mid) print(row("Risk:Reward", f"{tr.get('rr',0):.2f}", f"{te.get('rr',0):.2f}")) print(row("Expectancy", dol(tr.get("expect",0)), dol(te.get("expect",0)))) print(row("Largest Win", pct4(tr.get("best",0)), pct4(te.get("best",0)))) print(row("Largest Loss", pct4(tr.get("worst",0)), pct4(te.get("worst",0)))) print(row("Avg Trade Return", pct4(tr.get("avg",0)), pct4(te.get("avg",0)))) print(bot) else: print("Failed:", s.get("error", "unknown"))
Already have strategy code?
Paste it here and generation is skipped: Build and test goes straight to training.
Deploy and automate
Deploy a trained model so its live signals are delivered, by Telegram, Email, Discord or Webhook. The script lists your models, keeps the ones that pass your criteria, deploys them and prints what is live. The button deploys the model you just trained in Build and test.
import requests, json, webbrowser from IPython.display import display, HTML BASE = "https://api.quantifyme.ai" API_KEY = "qm_YOUR_KEY" # from "Get an API key" on this page H = {"X-API-Key": API_KEY, "Content-Type": "application/json"} # Deploy criteria DEPLOY = True # deploy models that pass criteria MIN_RETURN = 0.01 # 1% minimum test return MIN_PROFIT_FACTOR = 1.0 # minimum profit factor WEBHOOK_URL = "" # your webhook endpoint (optional) OPEN_IN_BROWSER = True # auto-open hub prediction tab after deploy SHOW_EMPTY = False # show models with 0 trades # Helper: check what is currently deployed def get_deployed(): return requests.get(f"{BASE}/api/v1/deployed", headers=H).json() # Fetch models, sort newest-first resp = requests.get(f"{BASE}/api/v1/models", headers=H).json() if "error" in resp: raise RuntimeError(f"API error: {resp['error']}: check API_KEY") all_models = resp.get("models", []) all_models.sort(key=lambda m: m.get("trained_at", "") or "", reverse=True) runs = [m for m in all_models if m.get("test_stats", {}).get("n", 0) > 0 or SHOW_EMPTY] hidden = len(all_models) - len(runs) tail = f" (hidden {hidden} with no backtest)" if hidden and not SHOW_EMPTY else "" print(f"Found {len(all_models)} model(s){tail}") print("─" * 84) print(f" {'Status':6s} {'Model':24s} {'Trained':17s} {'Return':>8s} {'PF':>6s} {'WR':>6s} {'Trades':>7s}") print("─" * 84) _opened = False # open only the first deployed URL for m in runs: test = m.get("test_stats", {}) ret, pf, wr, n = test.get("ret", 0), test.get("pf", 0), test.get("wr", 0), test.get("n", 0) stem = m["name"] display_name = (m.get("model_name") or stem)[:24] trained = ((m.get("trained_at") or "").replace("T", " "))[:16] passed = ret > MIN_RETURN and pf > MIN_PROFIT_FACTOR flag = "PASS" if passed else "SKIP" print(f" [{flag}] {display_name:24s} {trained:17s} {ret:>7.2%} {pf:>6.2f} {wr:>5.1%} {n:>7d}") if DEPLOY and passed: body = {"model_name": display_name, "channels": ["webhook"]} if WEBHOOK_URL: body["webhook_url"] = WEBHOOK_URL r = requests.post(f"{BASE}/api/v1/deploy", json=body, headers=H).json() if "error" in r: print(f" ✗ Error: {r['error']}") continue dep_stem = r.get("model", stem) live = get_deployed() confirmed = dep_stem in [d["model"] for d in live.get("deployed", [])] url = f"{BASE}/hfthub?tab=backtesting&model={dep_stem}&api_key={API_KEY}" print() # blank line before deploy message if confirmed: chans = ", ".join(r.get("channels", [])) print(f" ✓ DEPLOYED (live): {dep_stem} (channels: {chans})") display(HTML(f'<pre style="margin:0;font-family:monospace"> → <a href="{url}" target="_blank">Open live signal dashboard</a></pre>')) if OPEN_IN_BROWSER and not _opened: webbrowser.open(url) _opened = True else: print(f" ⚠ Deploy OK but not showing as live yet") print() # blank line after deploy message print("─" * 84) print() print("Currently deployed") live = get_deployed() if live.get("count", 0) == 0: print(" (none)") else: for d in live["deployed"]: chans = ", ".join(d.get("channels", [])) or "-" print(f" • {d['model']:30s} | channels: {chans:20s} | since: {d.get('created_at', '')[:19]}")
import requests, json, os, pathlib, webbrowser, http.server, socketserver, urllib.parse, threading, time from IPython.display import display, HTML BASE = "https://api.quantifyme.ai" def qm_login(base=BASE, timeout=30): # Layered auth: env var, then cache, then browser OAuth, then trial key # 1. Explicit env var if os.environ.get("QUANTIFYME_API_KEY"): return os.environ["QUANTIFYME_API_KEY"] # 2. Cached creds (~/.quantifyme/credentials.json) cache = pathlib.Path.home() / ".quantifyme" / "credentials.json" if cache.exists(): try: key = json.loads(cache.read_text()).get("api_key") if key: r = requests.get(f"{base}/api/v1/whoami-key", headers={"X-API-Key": key}, timeout=5) if r.ok: return key except Exception: pass # 3. Browser OAuth callback (only if hub running + browser available) received = {} class _H(http.server.BaseHTTPRequestHandler): def do_GET(self): q = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query) received["api_key"] = q.get("api_key", [None])[0] self.send_response(200); self.send_header("Content-Type", "text/plain"); self.end_headers() self.wfile.write(b"ok") def log_message(self, *a): pass try: server = socketserver.TCPServer(("127.0.0.1", 0), _H) port = server.server_address[1] threading.Thread(target=server.handle_request, daemon=True).start() webbrowser.open(f"{base}/auth/cli?cb=http://localhost:{port}/cb") for _ in range(timeout * 2): if received: break time.sleep(0.5) server.server_close() if received.get("api_key"): cache.parent.mkdir(exist_ok=True) cache.write_text(json.dumps({"api_key": received["api_key"]})) try: cache.chmod(0o600) except Exception: pass return received["api_key"] except Exception: pass # 4. Trial key fallback (works for AI agents, anonymous users, Colab) r = requests.post(f"{base}/api/v1/key/trial", timeout=10).json() key = r.get("api_key", "") if key: cache.parent.mkdir(exist_ok=True) cache.write_text(json.dumps({"api_key": key})) try: cache.chmod(0o600) except Exception: pass return key API_KEY = qm_login() print(f"Authenticated: {API_KEY[:12]}…") H = {"X-API-Key": API_KEY, "Content-Type": "application/json"} # Deploy criteria DEPLOY = True # deploy models that pass criteria MIN_RETURN = 0.01 # 1% minimum test return MIN_PROFIT_FACTOR = 1.0 # minimum profit factor WEBHOOK_URL = "" # your webhook endpoint (optional) OPEN_IN_BROWSER = True # auto-open hub prediction tab after deploy SHOW_EMPTY = False # show models with 0 trades # Helper: check what is currently deployed def get_deployed(): return requests.get(f"{BASE}/api/v1/deployed", headers=H).json() # Fetch models, sort newest-first resp = requests.get(f"{BASE}/api/v1/models", headers=H).json() if "error" in resp: raise RuntimeError(f"API error: {resp['error']}: check API_KEY") all_models = resp.get("models", []) all_models.sort(key=lambda m: m.get("trained_at", "") or "", reverse=True) runs = [m for m in all_models if m.get("test_stats", {}).get("n", 0) > 0 or SHOW_EMPTY] hidden = len(all_models) - len(runs) tail = f" (hidden {hidden} with no backtest)" if hidden and not SHOW_EMPTY else "" print(f"Found {len(all_models)} model(s){tail}") print("─" * 84) print(f" {'Status':6s} {'Model':24s} {'Trained':17s} {'Return':>8s} {'PF':>6s} {'WR':>6s} {'Trades':>7s}") print("─" * 84) _opened = False # open only the first deployed URL for m in runs: test = m.get("test_stats", {}) ret, pf, wr, n = test.get("ret", 0), test.get("pf", 0), test.get("wr", 0), test.get("n", 0) stem = m["name"] display_name = (m.get("model_name") or stem)[:24] trained = ((m.get("trained_at") or "").replace("T", " "))[:16] passed = ret > MIN_RETURN and pf > MIN_PROFIT_FACTOR flag = "PASS" if passed else "SKIP" print(f" [{flag}] {display_name:24s} {trained:17s} {ret:>7.2%} {pf:>6.2f} {wr:>5.1%} {n:>7d}") if DEPLOY and passed: body = {"model_name": display_name, "channels": ["webhook"]} if WEBHOOK_URL: body["webhook_url"] = WEBHOOK_URL r = requests.post(f"{BASE}/api/v1/deploy", json=body, headers=H).json() if "error" in r: print(f" ✗ Error: {r['error']}") continue dep_stem = r.get("model", stem) live = get_deployed() confirmed = dep_stem in [d["model"] for d in live.get("deployed", [])] url = f"{BASE}/hfthub?tab=backtesting&model={dep_stem}&api_key={API_KEY}" print() # blank line before deploy message if confirmed: chans = ", ".join(r.get("channels", [])) print(f" ✓ DEPLOYED (live): {dep_stem} (channels: {chans})") display(HTML(f'<pre style="margin:0;font-family:monospace"> → <a href="{url}" target="_blank">Open live signal dashboard</a></pre>')) if OPEN_IN_BROWSER and not _opened: webbrowser.open(url) _opened = True else: print(f" ⚠ Deploy OK but not showing as live yet") print() # blank line after deploy message print("─" * 84) print() print("Currently deployed") live = get_deployed() if live.get("count", 0) == 0: print(" (none)") else: for d in live["deployed"]: chans = ", ".join(d.get("channels", [])) or "-" print(f" • {d['model']:30s} | channels: {chans:20s} | since: {d.get('created_at', '')[:19]}")
The sign-in helper, qm_login(), tries four things in order: the QUANTIFYME_API_KEY environment variable, a cached key in ~/.quantifyme/credentials.json, a browser sign-in, and last a trial key, which is what works for an AI agent, an anonymous user or Colab.
Community script
A strategy shared on the community page, as one script: the first row of the leaderboard today. It was published on USDCAD 1 h data. Run it to see the result for yourself.
Signal Mix strategy on USD/CAD 1h. A compact, machine-selected indicator set; the classifier learns the entry rule directly from the features. Features: Z-score 20, ADX 20, Session/time features, RSI 14, Williams %R 21, CCI 14. Model: XGBoost; label horizon 1 bars, confidence threshold 0.52, direction short. Risk: 25 pip stop / 50 pip target (1:2 R/R), 1.0 lot on $10k, $6 round-trip commission. Trained on the last 40 days with a 70/30 holdout; the published numbers are the out-of-sample 30%.
- Net return
- Sharpe
- Max drawdown
- Trades
import requests, time BASE = "https://api.quantifyme.ai" API_KEY = "qm_YOUR_KEY" # from "Get an API key" on this page, or POST /api/v1/key/trial H = {"X-API-Key": API_KEY, "Content-Type": "application/json"} # Strategy: USD/CAD Signal Mix: Z-score 20 + ADX 20 (XGBoost, 1h) by @silver-bull-130 code = requests.get(f"{BASE}/api/v1/community/269/code", timeout=30).json()["code"] train = requests.post(f"{BASE}/api/v1/train", json={ "code": code, "model_name": "Community Demo", "train_split": 0.7, "symbol": "EURUSD", "timeframe": "15min" }, headers=H) job_id = train.json()["job_id"] while True: s = requests.get(f"{BASE}/api/v1/train/{job_id}", headers=H).json() print(s["status"]) if s["status"] == "done": m = s["metrics"] print(f"Return: {m['total_ret']:.2%}, Sharpe: {m['sharpe_strat']:.2f}") break elif s["status"] == "failed": print(s.get("error", "")) break time.sleep(3)
Example library
All 275 API examples, by section. Open one to read it. An example from a strategy builder section has an Add to composer button, which puts it in the matching slot of Build and test above.
Strategy builder
Feature engineering70
RSI
RSI 14 onlySingle indicator, RSI default period 14
# FE: RSI 14 only "features": "RSI 14", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14} # exact params enforcedRSI 7 (fast)Fast RSI for scalping
# FE: RSI 7 (fast) "features": "RSI 7", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 7} # exact params enforcedRSI 21 (slow)Slow RSI for swing trading
# FE: RSI 21 (slow) "features": "RSI 21", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 21} # exact params enforcedRSI 5 (ultra-fast)Ultra-fast RSI
# FE: RSI 5 (ultra-fast) "features": "RSI 5", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 5} # exact params enforced
MACD
MACD standard (12,26,9)Standard MACD
# FE: MACD standard (12,26,9) "features": "MACD (12,26,9)", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9} # exact params enforcedMACD fast (8,21,5)Faster MACD
# FE: MACD fast (8,21,5) "features": "MACD (8,21,5)", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 8, "macd_slow": 21, "macd_signal": 5} # exact params enforcedMACD slow (19,39,9)Slow MACD
# FE: MACD slow (19,39,9) "features": "MACD (19,39,9)", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 19, "macd_slow": 39, "macd_signal": 9} # exact params enforcedMACD ultra-fast (5,13,3)Ultra-fast MACD
# FE: MACD ultra-fast (5,13,3) "features": "MACD (5,13,3)", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 5, "macd_slow": 13, "macd_signal": 3} # exact params enforced
Bollinger Bands
BB standard (20,2)Standard BB
# FE: BB standard (20,2) "features": "Bollinger Bands (20,2)", # NL context for Claude "indicators": {"bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedBB tight (20,1.5)Tighter bands
# FE: BB tight (20,1.5) "features": "Bollinger Bands (20,1.5)", # NL context for Claude "indicators": {"bb_enabled": true, "bb_period": 20, "bb_std": 1.5} # exact params enforcedBB wide (20,2.5)Wider bands
# FE: BB wide (20,2.5) "features": "Bollinger Bands (20,2.5)", # NL context for Claude "indicators": {"bb_enabled": true, "bb_period": 20, "bb_std": 2.5} # exact params enforcedBB fast (10,2)Fast BB
# FE: BB fast (10,2) "features": "Bollinger Bands (10,2)", # NL context for Claude "indicators": {"bb_enabled": true, "bb_period": 10, "bb_std": 2.0} # exact params enforcedBB slow (50,2)Slow BB
# FE: BB slow (50,2) "features": "Bollinger Bands (50,2)", # NL context for Claude "indicators": {"bb_enabled": true, "bb_period": 50, "bb_std": 2.0} # exact params enforced
SMA
SMA 20/50/200Classic triple SMA
# FE: SMA 20/50/200 "features": "SMA 20, 50, 200", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "20,50,200"} # exact params enforcedSMA 10/30Fast SMA pair
# FE: SMA 10/30 "features": "SMA 10/30", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "10,30"} # exact params enforcedSMA 50/100/200Position trading SMA
# FE: SMA 50/100/200 "features": "SMA 50/100/200", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "50,100,200"} # exact params enforcedSMA single 200SMA 200 trend king
# FE: SMA single 200 "features": "SMA 200", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "200"} # exact params enforced
EMA
EMA 9/21/50Fast EMA trio
# FE: EMA 9/21/50 "features": "EMA 9/21/50", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "9,21,50"} # exact params enforcedEMA 50/200 (golden cross)Golden cross
# FE: EMA 50/200 (golden cross) "features": "EMA 50/200", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200"} # exact params enforcedEMA 5/13/34 (Fibonacci)Fibonacci EMA
# FE: EMA 5/13/34 (Fibonacci) "features": "EMA 5/13/34", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "5,13,34"} # exact params enforcedEMA 8/21 scalpingFast EMA scalping
# FE: EMA 8/21 scalping "features": "EMA 8/21", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "8,21"} # exact params enforced
WMA
WMA 20Weighted MA
# FE: WMA 20 "features": "WMA 20", # NL context for Claude "indicators": {"wma_enabled": true, "wma_periods": "20"} # exact params enforcedWMA 10/30WMA crossover
# FE: WMA 10/30 "features": "WMA 10/30", # NL context for Claude "indicators": {"wma_enabled": true, "wma_periods": "10,30"} # exact params enforced
Stochastic
Stochastic (14,3)Standard Stochastic
# FE: Stochastic (14,3) "features": "Stochastic (14,3)", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3} # exact params enforcedStochastic fast (5,3)Fast Stochastic
# FE: Stochastic fast (5,3) "features": "Stochastic (5,3)", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 5, "stoch_d": 3} # exact params enforcedStochastic slow (21,5)Slow Stochastic
# FE: Stochastic slow (21,5) "features": "Stochastic (21,5)", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 21, "stoch_d": 5} # exact params enforced
ATR
ATR 14Average True Range
# FE: ATR 14 "features": "ATR 14", # NL context for Claude "indicators": {"atr_enabled": true, "atr_period": 14} # exact params enforcedATR 7 (fast)Fast ATR
# FE: ATR 7 (fast) "features": "ATR 7", # NL context for Claude "indicators": {"atr_enabled": true, "atr_period": 7} # exact params enforcedATR 21 (slow)Slow ATR
# FE: ATR 21 (slow) "features": "ATR 21", # NL context for Claude "indicators": {"atr_enabled": true, "atr_period": 21} # exact params enforced
2-Indicator Combos
RSI + MACDMomentum + trend
# FE: RSI + MACD "features": "RSI 14, MACD (12,26,9)", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9} # exact params enforcedRSI + BBRSI + Bollinger
# FE: RSI + BB "features": "RSI 14, Bollinger Bands (20,2)", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedRSI + EMARSI + EMA trend
# FE: RSI + EMA "features": "RSI 14, EMA 50/200", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "ema_enabled": true, "ema_periods": "50,200"} # exact params enforcedRSI + ATRRSI + ATR sizing
# FE: RSI + ATR "features": "RSI 14, ATR 14", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "atr_enabled": true, "atr_period": 14} # exact params enforcedRSI + StochasticDouble oscillator
# FE: RSI + Stochastic "features": "RSI 14, Stochastic (14,3)", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3} # exact params enforcedMACD + BBMACD + Bollinger
# FE: MACD + BB "features": "MACD (12,26,9), Bollinger Bands (20,2)", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedMACD + ATRMACD + ATR
# FE: MACD + ATR "features": "MACD (12,26,9), ATR 14", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforcedMACD + EMAMACD + EMA
# FE: MACD + EMA "features": "MACD (12,26,9), EMA 50/200", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "ema_enabled": true, "ema_periods": "50,200"} # exact params enforcedEMA + BBEMA + Bollinger
# FE: EMA + BB "features": "EMA 50/200, Bollinger Bands (20,2)", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200", "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedEMA + ATREMA + ATR
# FE: EMA + ATR "features": "EMA 50/200, ATR 14", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200", "atr_enabled": true, "atr_period": 14} # exact params enforcedSMA + RSISMA + RSI
# FE: SMA + RSI "features": "SMA 50/200, RSI 14", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "50,200", "rsi_enabled": true, "rsi_period": 14} # exact params enforcedStoch + BBStochastic + BB
# FE: Stoch + BB "features": "Stochastic (14,3), Bollinger Bands (20,2)", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedStoch + ATRStochastic + ATR
# FE: Stoch + ATR "features": "Stochastic (14,3), ATR 14", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "atr_enabled": true, "atr_period": 14} # exact params enforcedSMA + EMA comboSMA trend+EMA entries
# FE: SMA + EMA combo "features": "SMA 200, EMA 9/21", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "200", "ema_enabled": true, "ema_periods": "9,21"} # exact params enforced
3-4 Indicator Combos
RSI + MACD + BBTriple combo
# FE: RSI + MACD + BB "features": "RSI 14, MACD (12,26,9), Bollinger Bands (20,2)", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedRSI + MACD + ATRMomentum+trend+vol
# FE: RSI + MACD + ATR "features": "RSI 14, MACD (12,26,9), ATR 14", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforcedRSI + EMA + ATRRSI+EMA+ATR
# FE: RSI + EMA + ATR "features": "RSI 14, EMA 50/200, ATR 14", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "ema_enabled": true, "ema_periods": "50,200", "atr_enabled": true, "atr_period": 14} # exact params enforcedMACD + BB + ATRTrend+vol+sizing
# FE: MACD + BB + ATR "features": "MACD (12,26,9), BB (20,2), ATR 14", # NL context for Claude "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "atr_enabled": true, "atr_period": 14} # exact params enforcedEMA + BB + RSITrend+vol+momentum
# FE: EMA + BB + RSI "features": "EMA 50/200, BB (20,2), RSI 14", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200", "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "rsi_enabled": true, "rsi_period": 14} # exact params enforcedStoch + RSI + BBDouble osc+vol
# FE: Stoch + RSI + BB "features": "Stochastic (14,3), RSI 14, BB (20,2)", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "rsi_enabled": true, "rsi_period": 14, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedStoch + MACD + ATROsc+trend+vol
# FE: Stoch + MACD + ATR "features": "Stochastic (14,3), MACD (12,26,9), ATR 14", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforcedRSI+MACD+BB+ATRFull quad
# FE: RSI+MACD+BB+ATR "features": "RSI 14, MACD, BB, ATR", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "atr_enabled": true, "atr_period": 14} # exact params enforcedRSI+MACD+EMA+ATRMomentum+trend+vol
# FE: RSI+MACD+EMA+ATR "features": "RSI 14, MACD, EMA 50/200, ATR 14", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "ema_enabled": true, "ema_periods": "50,200", "atr_enabled": true, "atr_period": 14} # exact params enforcedStoch+RSI+MACD+ATRDouble osc+trend+vol
# FE: Stoch+RSI+MACD+ATR "features": "Stoch, RSI, MACD, ATR", # NL context for Claude "indicators": {"stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforcedEMA+SMA+BB+RSIDouble MA+vol+momentum
# FE: EMA+SMA+BB+RSI "features": "EMA 9/21, SMA 50/200, BB, RSI", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "9,21", "sma_enabled": true, "sma_periods": "50,200", "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "rsi_enabled": true, "rsi_period": 14} # exact params enforced
All Indicators
All 5 coreRSI+MACD+BB+Stoch+ATR
# FE: All 5 core "features": "All 5 core indicators", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "atr_enabled": true, "atr_period": 14} # exact params enforcedAll 8 (kitchen sink)Every indicator
# FE: All 8 (kitchen sink) "features": "All 8 indicators", # NL context for Claude "indicators": {"sma_enabled": true, "sma_periods": "20,50,200", "ema_enabled": true, "ema_periods": "9,21,50", "wma_enabled": true, "wma_periods": "20", "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "atr_enabled": true, "atr_period": 14} # exact params enforced
Strategy Sets
Fast scalping setAll fast-period
# FE: Fast scalping set "features": "Fast scalping", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 5, "macd_enabled": true, "macd_fast": 5, "macd_slow": 13, "macd_signal": 3, "bb_enabled": true, "bb_period": 10, "bb_std": 1.5, "stoch_enabled": true, "stoch_k": 5, "stoch_d": 3, "ema_enabled": true, "ema_periods": "5,13", "atr_enabled": true, "atr_period": 7} # exact params enforcedSlow swing setAll slow-period
# FE: Slow swing set "features": "Slow swing", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 21, "macd_enabled": true, "macd_fast": 19, "macd_slow": 39, "macd_signal": 9, "bb_enabled": true, "bb_period": 50, "bb_std": 2.5, "stoch_enabled": true, "stoch_k": 21, "stoch_d": 5, "sma_enabled": true, "sma_periods": "50,100,200", "atr_enabled": true, "atr_period": 21} # exact params enforcedFibonacci setFibonacci periods
# FE: Fibonacci set "features": "Fibonacci indicators", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 13, "ema_enabled": true, "ema_periods": "5,8,13,21,34", "bb_enabled": true, "bb_period": 21, "bb_std": 2.0, "stoch_enabled": true, "stoch_k": 13, "stoch_d": 3, "atr_enabled": true, "atr_period": 13} # exact params enforcedMean reversion setOscillators+bands
# FE: Mean reversion set "features": "Mean reversion", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforcedTrend following setMAs+MACD+ATR
# FE: Trend following set "features": "Trend following", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200", "sma_enabled": true, "sma_periods": "200", "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforced
Natural Language
NL, price actionCandle patterns
# FE: NL: price action "features": "Candle body ratio, wicks, engulfing, doji, hammer/shooting star, consecutive bull/bear count", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, volumeVolume features
# FE: NL: volume "features": "Volume Z-score, volume momentum, OBV, volume spike detection", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, multi-timeframeMulti-TF
# FE: NL: multi-timeframe "features": "15-min RSI 14, 1-hour SMA 50 trend, 4-hour support/resistance", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, returnsStatistical returns
# FE: NL: returns "features": "Log returns (1,3,5,10,20 bar), momentum, volatility, z-score", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, sessionTime features
# FE: NL: session "features": "Hour sin/cos, day of week, is_london, is_ny, is_overlap", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, S/R levelsPrice structure
# FE: NL: S/R levels "features": "Distance from 20-bar high/low, pivot points, level touches", # NL only: Claude interprets freely "indicators": {} # no structured paramsNL, order flowOrder flow proxies
# FE: NL: order flow "features": "CLV, A/D line, Chaikin Money Flow, buying/selling pressure", # NL only: Claude interprets freely "indicators": {} # no structured params
NL + Structured
NL + structuredNL custom+structured
# FE: NL + structured "features": "Volume Z-score, candle body ratio", # NL context for Claude "indicators": {"rsi_enabled": true, "rsi_period": 14, "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "atr_enabled": true, "atr_period": 14} # exact params enforcedNL + structured sessionSession NL+indicators
# FE: NL + structured session "features": "Hour sin/cos, is_london, is_overlap", # NL context for Claude "indicators": {"ema_enabled": true, "ema_periods": "50,200", "rsi_enabled": true, "rsi_period": 14, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0} # exact params enforced
Signal and entry41
MACD
MACD crossoverBuy on MACD cross above signal, sell on cross below
# SIG: MACD crossover "signals": "Buy when MACD line crosses above signal line, sell when crosses below"
MACD zero crossBuy on MACD crossing above zero, sell below
# SIG: MACD zero cross "signals": "Buy when MACD histogram crosses above zero, sell when crosses below zero"
MACD histogram reversalTrade MACD histogram direction change
# SIG: MACD histogram reversal "signals": "Buy when MACD histogram starts increasing (reversal from negative), sell when starts decreasing"
MACD divergenceTrade MACD divergence with price
# SIG: MACD divergence "signals": "Buy on bullish divergence (price lower low but MACD higher low), sell on bearish divergence"
RSI
RSI oversold/overboughtClassic RSI threshold signals
# SIG: RSI oversold/overbought "signals": "Buy when RSI crosses above 30 (leaving oversold), sell when RSI crosses below 70 (leaving overbought)"
RSI extreme (20/80)Tighter RSI thresholds for stronger signals
# SIG: RSI extreme (20/80) "signals": "Buy when RSI < 20, sell when RSI > 80"
RSI midline crossRSI 50 as trend filter
# SIG: RSI midline cross "signals": "Buy when RSI crosses above 50, sell when crosses below 50"
RSI divergenceRSI divergence with price
# SIG: RSI divergence "signals": "Buy on bullish RSI divergence (price new low, RSI higher low), sell on bearish divergence"
Bollinger Bands
BB breakoutTrade Bollinger Band breakouts
# SIG: BB breakout "signals": "Buy when price breaks above upper Bollinger Band, sell when breaks below lower band"
BB mean reversionFade BB extremes back to middle
# SIG: BB mean reversion "signals": "Buy when price touches lower BB and starts rising, sell when touches upper BB and starts falling. Target: BB mid"
BB squeeze breakoutTrade BB squeeze (low volatility breakout)
# SIG: BB squeeze breakout "signals": "Buy when BB width is at 20-bar low and price breaks above upper band, sell on break below lower band"
BB %B thresholdTrade based on BB percent B position
# SIG: BB %B threshold "signals": "Buy when %B < 0.1 (near lower band), sell when %B > 0.9 (near upper band)"
MA Crossover
EMA golden/death crossEMA 50/200 crossover
# SIG: EMA golden/death cross "signals": "Buy on golden cross (EMA 50 crosses above EMA 200), sell on death cross (EMA 50 crosses below)"
EMA fast cross (8/21)Fast EMA crossover for scalping
# SIG: EMA fast cross (8/21) "signals": "Buy when EMA 8 crosses above EMA 21, sell when crosses below"
SMA triple crossSMA 20/50/200 alignment
# SIG: SMA triple cross "signals": "Buy when SMA 20 > SMA 50 > SMA 200 (all aligned bullish), sell when reversed"
Price above/below MA200Simple trend filter
# SIG: Price above/below MA200 "signals": "Buy when price closes above SMA 200, sell when closes below"
MA ribbon expansionTrade when MAs fan out
# SIG: MA ribbon expansion "signals": "Buy when EMA 9 > EMA 21 > EMA 50 and gap between them is widening, sell when reversed"
Stochastic
Stochastic crossK/D crossover in extreme zones
# SIG: Stochastic cross "signals": "Buy when %K crosses above %D below 20 (oversold), sell when %K crosses below %D above 80 (overbought)"
Stochastic extremeSimple threshold
# SIG: Stochastic extreme "signals": "Buy when Stochastic < 10, sell when > 90"
Stochastic midline50 level crossover
# SIG: Stochastic midline "signals": "Buy when Stochastic K crosses above 50, sell when crosses below 50"
Momentum
Momentum reversalTrade momentum shifts
# SIG: Momentum reversal "signals": "Buy when momentum turns positive after being negative for 5+ bars, sell on opposite"
Price rejectionCandle wick rejection signals
# SIG: Price rejection "signals": "Buy on hammer candle (long lower wick > 2x body, bullish close), sell on shooting star (long upper wick)"
Engulfing patternBullish/bearish engulfing
# SIG: Engulfing pattern "signals": "Buy on bullish engulfing (current bar body fully engulfs previous bearish bar), sell on bearish engulfing"
BreakoutRange breakout
# SIG: Breakout "signals": "Buy when price breaks above 50-bar high, sell when breaks below 50-bar low"
Combined
MACD + RSI confirmMACD crossover confirmed by RSI
# SIG: MACD + RSI confirm "signals": "Buy when MACD crosses above signal AND RSI < 60 (not overbought), sell when MACD crosses below AND RSI > 40"
RSI + BB confirmRSI oversold at lower BB
# SIG: RSI + BB confirm "signals": "Buy when RSI < 30 AND price near lower Bollinger Band, sell when RSI > 70 AND price near upper BB"
MA cross + RSI filterMA crossover filtered by RSI
# SIG: MA cross + RSI filter "signals": "Buy on EMA 50/200 golden cross only if RSI > 50, sell on death cross only if RSI < 50"
Stoch + BBStochastic in BB extremes
# SIG: Stoch + BB "signals": "Buy when Stochastic < 20 and price below lower BB, sell when Stochastic > 80 and price above upper BB"
MACD + BB squeezeMACD direction after BB squeeze
# SIG: MACD + BB squeeze "signals": "Buy when BB width at 20-bar low and MACD histogram turns positive, sell when turns negative"
Triple confirmRSI + MACD + MA all agree
# SIG: Triple confirm "signals": "Buy when RSI > 50 AND MACD above signal AND price above EMA 200. Sell when all three reverse"
Session
London open entryTrade first 30 min of London
# SIG: London open entry "signals": "Only enter during first 30 minutes of London session (08:00-08:30 UTC). Buy/sell based on breakout of first 15-min range"
NY open momentumTrade NY open direction
# SIG: NY open momentum "signals": "Buy if price > prior bar close in first 15 min of NY open (14:30 UTC), sell if price < prior close"
No Friday tradesAvoid weekend risk
# SIG: No Friday trades "signals": "Normal signal logic but close all positions Friday 18:00 UTC, no new entries after Friday 16:00"
Overlap onlyLondon-NY overlap
# SIG: Overlap only "signals": "Only trade during London-NY overlap (13:00-17:00 UTC), flat outside"
Threshold
High confidence onlyStrict threshold
# SIG: High confidence only "signals": "Only enter when model confidence > 70%. Exit when confidence drops below 55%"
Aggressive entryLow threshold
# SIG: Aggressive entry "signals": "Enter on any model confidence > 50%. Stay in trade as long as signal direction unchanged"
Scaled entrySize by confidence
# SIG: Scaled entry "signals": "Enter with 50% size at confidence > 55%, full size at > 65%. Exit at < 50%"
Natural Language
NL, trend pullbackBuy dips in uptrend
# SIG: NL: trend pullback "signals": "In an uptrend (price above SMA 200), buy when price pulls back to SMA 50 and bounces (close > open after touching SMA 50)"
NL, volatility breakoutTrade volatility expansion
# SIG: NL: volatility breakout "signals": "Enter long when ATR suddenly increases (current ATR > 1.5x 20-bar average ATR) and price is trending up. Enter short if trending down."
NL, range tradingTrade within range
# SIG: NL: range trading "signals": "Identify 50-bar range (high-low). Buy near range bottom, sell near range top. Exit if range breaks."
NL, news avoidanceSkip high-impact times
# SIG: NL: news avoidance "signals": "Normal MACD crossover signals but skip any signal within 30 minutes of hourly bar boundaries (common news release times)"
ML model23
Tree-Based
Random ForestEnsemble of decision trees, robust, handles noise well
# ML: Random Forest "model": "Random Forest"
Random Forest (1000 trees)Large ensemble for more stability
# ML: Random Forest (1000 trees) "model": "Random Forest with 1000 estimators, max depth 8"
Random Forest (shallow)Shallow trees to prevent overfitting
# ML: Random Forest (shallow) "model": "Random Forest with max depth 3, min samples leaf 20"
XGBoostGradient boosted trees, fast, accurate, popular in competitions
# ML: XGBoost "model": "XGBoost"
XGBoost (tuned)XGBoost with specific hyperparameters
# ML: XGBoost (tuned) "model": "XGBoost with 300 estimators, max depth 4, learning rate 0.05, subsample 0.8"
XGBoost (conservative)XGBoost tuned to avoid overfitting
# ML: XGBoost (conservative) "model": "XGBoost with max depth 3, learning rate 0.01, 500 estimators, early stopping"
Gradient BoostingSklearn gradient boosting, slower but reliable
# ML: Gradient Boosting "model": "Gradient Boosting"
Gradient Boosting (tuned)Tuned gradient boosting
# ML: Gradient Boosting (tuned) "model": "Gradient Boosting with 200 estimators, max depth 4, learning rate 0.05, subsample 0.8"
Linear
Logistic RegressionSimple linear classifier, fast, interpretable
# ML: Logistic Regression "model": "Logistic Regression"
Logistic Regression (balanced)Handle class imbalance
# ML: Logistic Regression (balanced) "model": "Logistic Regression with balanced class weights"
Logistic Regression (L1)Sparse features, L1 regularization
# ML: Logistic Regression (L1) "model": "Logistic Regression with L1 penalty (Lasso) for feature selection"
Ridge ClassifierL2 regularized linear
# ML: Ridge Classifier "model": "Ridge Classifier: linear model with L2 regularization"
Auto
Let Claude decideAI picks the best model for your strategy
# ML: Let Claude decide "model": "Let Claude decide"
Let Claude decide (ensemble)AI picks and combines models
# ML: Let Claude decide (ensemble) "model": "Let Claude decide: prefer ensemble methods for robustness"
Strategy-Specific
XGBoost for scalpingFast model for high-frequency
# ML: XGBoost for scalping "model": "XGBoost with shallow trees (max depth 3), fast learning rate 0.1, 100 estimators: optimized for speed on 1-min data"
RF for swing tradingStable model for longer holds
# ML: RF for swing trading "model": "Random Forest with 500 trees, max depth 10, balanced class weights: optimized for daily/hourly swing trades"
Logistic for trend followingSimple model for clear trends
# ML: Logistic for trend following "model": "Logistic Regression: simple and fast, works well when signal is strong and features are well-engineered"
XGBoost for mean reversionTuned for range-bound markets
# ML: XGBoost for mean reversion "model": "XGBoost with balanced class weights, max depth 4, learning rate 0.03: tuned for detecting overbought/oversold reversals"
Class Weights
Balanced class weightsHandle unequal buy/sell/hold distribution
# ML: Balanced class weights "model": "XGBoost with class_weight='balanced': adjusts for imbalanced signal distribution"
Custom class weightsWeight buys higher than sells
# ML: Custom class weights "model": "Random Forest with custom class weights: {-1: 1.0, 0: 0.5, 1: 1.5}: prioritize catching buy signals"
Natural Language
NL, best for noisy dataDescribe what you need
# ML: NL: best for noisy data "model": "Use a model that handles noisy financial data well, resistant to overfitting, with good generalization on unseen bars"
NL, fast inferenceSpeed priority
# ML: NL: fast inference "model": "Fast model: inference must be under 1ms per bar. Prefer simple model over complex ensemble."
NL, interpretableNeed to understand why
# ML: NL: interpretable "model": "Interpretable model: I need to understand which features drive each prediction. Feature importance must be meaningful."
Optimisation28
Return
Maximize Sharpe ratioRisk-adjusted return, the gold standard
# OPT: Maximize Sharpe ratio "optimization": "Maximize Sharpe ratio"
Maximize returnPure return, no risk adjustment
# OPT: Maximize return "optimization": "Maximize total return"
Maximize Calmar ratioReturn relative to max drawdown
# OPT: Maximize Calmar ratio "optimization": "Maximize Calmar ratio"
Maximize Sortino ratioLike Sharpe but only penalizes downside volatility
# OPT: Maximize Sortino ratio "optimization": "Maximize Sortino ratio: penalize downside risk only"
Maximize profit factorGross profit / gross loss
# OPT: Maximize profit factor "optimization": "Maximize profit factor (gross wins / gross losses)"
Risk
Minimize max drawdownProtect capital above all
# OPT: Minimize max drawdown "optimization": "Minimize maximum drawdown"
MDD < 10%Hard drawdown constraint
# OPT: MDD < 10% "optimization": "Maximize return with max drawdown under 10%"
MDD < 5%Very tight drawdown
# OPT: MDD < 5% "optimization": "Maximize Sharpe with max drawdown under 5%"
Minimize volatilityLow-volatility strategy
# OPT: Minimize volatility "optimization": "Minimize return volatility (standard deviation of returns)"
Win Rate
Maximize win rateConsistency, win more trades than lose
# OPT: Maximize win rate "optimization": "Maximize win rate"
Win rate > 55%Minimum win rate constraint
# OPT: Win rate > 55% "optimization": "Maximize Sharpe ratio with win rate above 55%"
Win rate > 60%High win rate constraint
# OPT: Win rate > 60% "optimization": "Maximize return with win rate above 60%"
Combined
Sharpe > 1, MDD < 10%Balanced, good risk-adjusted with drawdown cap
# OPT: Sharpe > 1, MDD < 10% "optimization": "Sharpe > 1 with MDD < 10%"
Sharpe > 1.5, MDD < 15%Higher bar for Sharpe
# OPT: Sharpe > 1.5, MDD < 15% "optimization": "Sharpe ratio above 1.5, max drawdown under 15%"
High Sharpe + high win rateBest of both
# OPT: High Sharpe + high win rate "optimization": "Maximize Sharpe ratio while keeping win rate above 55%"
Return + low drawdownAggressive with safety net
# OPT: Return + low drawdown "optimization": "Maximize total return, but keep max drawdown under 12%"
Calmar > 2Strong return/drawdown ratio
# OPT: Calmar > 2 "optimization": "Calmar ratio above 2: return must be at least 2x the max drawdown"
Trade Frequency
Many tradesHigh frequency, more statistical significance
# OPT: Many trades "optimization": "Maximize Sharpe with at least 50 trades in the test period"
Few high-quality tradesLow frequency, only the best setups
# OPT: Few high-quality trades "optimization": "Maximize profit per trade, minimum 10 trades, win rate > 60%"
Balanced frequencyNot too many, not too few
# OPT: Balanced frequency "optimization": "Maximize Sharpe with 20-40 trades in the test period"
Hyperparameters
Conservative depthPrevent overfitting with shallow trees
# OPT: Conservative depth "optimization": "Maximize Sharpe: use conservative hyperparameters: max depth 3-5, high regularization"
Aggressive depthAllow complex patterns
# OPT: Aggressive depth "optimization": "Maximize return: allow deeper trees (max depth 8-10) for capturing complex patterns"
Balanced class weightsHandle signal imbalance
# OPT: Balanced class weights "optimization": "Maximize Sharpe with balanced class weights: equal importance to buy, sell, and hold signals"
Early stoppingPrevent overfitting
# OPT: Early stopping "optimization": "Maximize Sharpe with early stopping: stop training when validation metric stops improving"
Natural Language
NL, robust to regime changeSurvive different market conditions
# OPT: NL: robust to regime change "optimization": "Optimize for consistency across different market regimes: strategy should work in trending AND ranging markets"
NL, low correlation to buy-and-holdIndependent alpha
# OPT: NL: low correlation to buy-and-hold "optimization": "Maximize alpha: returns should have low correlation with buy-and-hold. Strategy adds value beyond just holding."
NL, smooth equity curveNo big jumps or drops
# OPT: NL: smooth equity curve "optimization": "Optimize for smooth equity curve: minimize daily return variance, avoid large single-trade impacts"
NL, overnight riskMinimize gap exposure
# OPT: NL: overnight risk "optimization": "Minimize exposure during market close hours. Strategy should be flat or reduced size during low-liquidity periods."
Risk management26
Stop Loss
Stop loss 0.3%Tight stop, exit when position loses 0.3%
# RISK: Stop loss 0.3% "risk": "Stop loss 0.3%"
Stop loss 0.5%Medium stop
# RISK: Stop loss 0.5% "risk": "Stop loss 0.5%"
Stop loss 1%Wide stop, more room to breathe
# RISK: Stop loss 1% "risk": "Stop loss 1%"
Stop loss 20 pipsPip-based stop for EURUSD
# RISK: Stop loss 20 pips "risk": "Stop loss 20 pips (0.0020)"
ATR-based stopDynamic stop, wider when volatile
# RISK: ATR-based stop "risk": "Stop loss = 2x ATR(14). Wider stop in volatile markets, tighter in quiet."
Trailing stop 0.3%Lock in profits as price moves
# RISK: Trailing stop 0.3% "risk": "Trailing stop loss 0.3%: moves with price, locks in profits"
Take Profit
TP 0.5%Fixed take profit
# RISK: TP 0.5% "risk": "Take profit 0.5%"
2:1 reward/riskTP is 2x the stop loss
# RISK: 2:1 reward/risk "risk": "Stop loss 0.3%, take profit 0.6%: 2:1 reward to risk ratio"
3:1 reward/riskTP is 3x the stop loss
# RISK: 3:1 reward/risk "risk": "Stop loss 0.3%, take profit 0.9%: 3:1 reward to risk ratio"
ATR-based TPDynamic take profit
# RISK: ATR-based TP "risk": "Take profit = 3x ATR(14), stop loss = 1.5x ATR(14)"
Position Sizing
Fixed 1% riskRisk 1% of capital per trade
# RISK: Fixed 1% risk "risk": "Fixed 1% risk per trade: position size calculated from stop loss distance"
Fixed 2% riskRisk 2% per trade
# RISK: Fixed 2% risk "risk": "Fixed 2% risk per trade"
Kelly sizingKelly criterion, optimal sizing
# RISK: Kelly sizing "risk": "Kelly position sizing: size based on win rate and avg win/loss ratio"
Half KellyConservative Kelly
# RISK: Half Kelly "risk": "Half Kelly position sizing: half of Kelly optimal for safety"
ATR-based sizingSize inversely to volatility
# RISK: ATR-based sizing "risk": "Position size = 1% account risk / ATR(14). Smaller when volatile, larger when quiet."
Fixed lotSimple fixed size
# RISK: Fixed lot "risk": "Fixed 1.0 lot per trade, no dynamic sizing"
Frequency
Max 3 trades/dayLimit daily trades
# RISK: Max 3 trades/day "risk": "Max 3 trades per day"
Max 5 trades/dayMore active daily limit
# RISK: Max 5 trades/day "risk": "Max 5 trades per day"
Max 1 trade/dayOne shot per day
# RISK: Max 1 trade/day "risk": "Max 1 trade per day: wait for the best setup"
Combined
SL + TP + sizingFull risk package
# RISK: SL + TP + sizing "risk": "Stop loss 0.3%, take profit 0.6%, fixed 1% risk per trade"
ATR-based everythingFull ATR risk
# RISK: ATR-based everything "risk": "ATR-based stop (1.5x ATR), ATR-based TP (3x ATR), position size = 1% / ATR"
Conservative fullLow risk setup
# RISK: Conservative full "risk": "Stop loss 0.2%, take profit 0.6%, max 2 trades/day, half Kelly sizing"
Aggressive fullHigh risk setup
# RISK: Aggressive full "risk": "Stop loss 0.5%, take profit 1.5%, Kelly sizing, no daily limit"
Natural Language
NL, scale down on losing streakReduce size after losses
# RISK: NL: scale down on losing streak "risk": "After 3 consecutive losing trades, reduce position size by 50%. Reset after a winner."
NL, no overnightClose before market quiet
# RISK: NL: no overnight "risk": "Close all positions before 21:00 UTC (before forex daily rollover). No new entries after 20:30."
NL, volatility filterSkip low-vol periods
# RISK: NL: volatility filter "risk": "Skip trades when ATR(14) is below its 50-bar average: not enough movement to be worth the spread"
Position rules17
Direction
Both directionsLong and short
# POS: Both directions "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0}Long onlyOnly buy
# POS: Long only "pos_rules": {"max_pos": 1, "direction": "long", "on_opposite": "close_only", "cooldown": 0}Short onlyOnly sell
# POS: Short only "pos_rules": {"max_pos": 1, "direction": "short", "on_opposite": "close_only", "cooldown": 0}
On Opposite
Reverse on oppositeFlip direction immediately
# POS: Reverse on opposite "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0}Close only on oppositeExit to flat, don't flip
# POS: Close only on opposite "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "close_only", "cooldown": 0}Ignore oppositeStay in trade, ignore reversals
# POS: Ignore opposite "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "ignore", "cooldown": 0}
Max Positions
1 position maxSingle position at a time
# POS: 1 position max "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0}2 concurrentAllow 2 trades at once
# POS: 2 concurrent "pos_rules": {"max_pos": 2, "direction": "both", "on_opposite": "reverse", "cooldown": 0}3 concurrentAllow 3 trades at once
# POS: 3 concurrent "pos_rules": {"max_pos": 3, "direction": "both", "on_opposite": "reverse", "cooldown": 0}
Cooldown
No cooldownRe-enter immediately
# POS: No cooldown "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 0}2-bar cooldownWait 2 bars after exit
# POS: 2-bar cooldown "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 2}5-bar cooldownWait 5 bars
# POS: 5-bar cooldown "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 5}10-bar cooldownLong cooldown, avoid overtrading
# POS: 10-bar cooldown "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "reverse", "cooldown": 10}
Combos
Conservative longLong only + close on opposite + cooldown
# POS: Conservative long "pos_rules": {"max_pos": 1, "direction": "long", "on_opposite": "close_only", "cooldown": 3}Aggressive scalperBoth directions + reverse + no cooldown
# POS: Aggressive scalper "pos_rules": {"max_pos": 2, "direction": "both", "on_opposite": "reverse", "cooldown": 0}Patient swingIgnore opposite + long cooldown
# POS: Patient swing "pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "ignore", "cooldown": 10}Multi-position trend3 positions + long only
# POS: Multi-position trend "pos_rules": {"max_pos": 3, "direction": "long", "on_opposite": "close_only", "cooldown": 5}
Custom filter23
Session
London session onlyTrade only during London hours
# FILTER: London session only "risk_function": "Only trade during London session (08:00-16:00 UTC)"
NY session onlyTrade only during NY hours
# FILTER: NY session only "risk_function": "Only trade during New York session (13:00-21:00 UTC)"
London-NY overlapBest liquidity hours
# FILTER: London-NY overlap "risk_function": "Only trade during London-NY overlap (13:00-17:00 UTC)"
No Asian sessionSkip quiet hours
# FILTER: No Asian session "risk_function": "No trading during Asian session (22:00-08:00 UTC)"
First hour of LondonTrade the open momentum
# FILTER: First hour of London "risk_function": "Only take trades in first hour of London (08:00-09:00 UTC)"
Day
No Friday tradesAvoid weekend gap risk
# FILTER: No Friday trades "risk_function": "No new entries on Friday after 16:00 UTC. Close all positions by 20:00 UTC Friday."
No Monday morningSkip Monday gap reaction
# FILTER: No Monday morning "risk_function": "No trades on Monday before 10:00 UTC: let the market settle after weekend gap"
Weekdays only (no weekend)Standard forex week
# FILTER: Weekdays only (no weekend) "risk_function": "Only trade Monday 00:00 to Friday 20:00 UTC"
Tue-Thu onlyMid-week only
# FILTER: Tue-Thu only "risk_function": "Only trade Tuesday through Thursday: skip Monday gaps and Friday squeezes"
Volatility
High ATR onlyNeed movement to profit
# FILTER: High ATR only "risk_function": "Only trade when ATR(14) is above its 20-bar average: need volatility for the trade to work"
Low ATR skipSkip dead markets
# FILTER: Low ATR skip "risk_function": "Skip any signal when ATR(14) < 0.0003: spread will eat the profit"
BB squeeze skipAvoid range-bound
# FILTER: BB squeeze skip "risk_function": "Skip signals when Bollinger Band width is below 20-bar low: market is too compressed"
Scale by volatilityLess size when wild
# FILTER: Scale by volatility "risk_function": "Reduce position size by 50% when ATR is above 1.5x its average: lower risk in volatile conditions"
Trend
Only with trendNo counter-trend trades
# FILTER: Only with trend "risk_function": "Only take long signals when price is above SMA 200, only take short signals below SMA 200"
No counter-trendStrict trend following
# FILTER: No counter-trend "risk_function": "Skip any buy signal when EMA 50 is below EMA 200 (downtrend). Skip sells in uptrend."
Momentum confirmNeed momentum behind signal
# FILTER: Momentum confirm "risk_function": "Only take signals when 5-bar momentum is in the same direction as the signal"
Loss
Stop after 3 lossesDrawdown circuit breaker
# FILTER: Stop after 3 losses "risk_function": "After 3 consecutive losing trades in a day, stop trading for the rest of the day"
Daily loss limitCap daily losses
# FILTER: Daily loss limit "risk_function": "Stop trading for the day if total daily loss exceeds 1% of capital"
Reduce after drawdownScale down in drawdown
# FILTER: Reduce after drawdown "risk_function": "If equity is in a 5% drawdown from peak, reduce position size by 50% until new high"
Cost
Wide spread skipProtect against bad fills
# FILTER: Wide spread skip "risk_function": "Skip signals when spread is above 2 pips (0.0002): likely low liquidity"
News time skipAvoid slippage
# FILTER: News time skip "risk_function": "No trades within 30 minutes before or after the hour mark (common news release times)"
Combined
London + ATR + trendTriple filter
# FILTER: London + ATR + trend "risk_function": "Only trade London session (08-16 UTC), when ATR > average, and price above SMA 200 for longs / below for shorts"
Full safety netMaximum protection
# FILTER: Full safety net "risk_function": "London-NY overlap only, no Friday after 16:00, skip when ATR < average, stop after 3 consecutive losses, daily loss limit 1%"
Backtesting
Backtest config22
Default (beginner)Default config, $10K capital, 1 lot, 30x leverage, 55% threshold
"capital": 10000, "lot_size": 1.0, "leverage": 30, "confidence_threshold": 55, "commission": 6.0, "swap_long": -1.0, "swap_short": 0.3, "timeframe": "15min"
ConservativeLower leverage, tighter threshold
"capital": 10000, "lot_size": 0.5, "leverage": 50, "confidence_threshold": 65, "commission": 6.0, "swap_long": -1.0, "swap_short": 0.3, "timeframe": "15min"
AggressiveHigher leverage, lower threshold
"capital": 10000, "lot_size": 2.0, "leverage": 200, "confidence_threshold": 50, "commission": 6.0, "swap_long": -1.0, "swap_short": 0.3, "timeframe": "15min"
Micro account$1K capital, 0.1 lot
"capital": 1000, "lot_size": 0.1, "leverage": 100, "confidence_threshold": 55, "commission": 0.6, "swap_long": -0.1, "swap_short": 0.03, "timeframe": "15min"
Large account$100K capital, 10 lots
"capital": 100000, "lot_size": 10.0, "leverage": 100, "confidence_threshold": 60, "commission": 60.0, "swap_long": -10.0, "swap_short": 3.0, "timeframe": "15min"
1-min scalping1-minute timeframe
"timeframe": "1min", "confidence_threshold": 50
5-min intraday5-minute timeframe
"timeframe": "5min", "confidence_threshold": 55
1-hour swing1-hour timeframe
"timeframe": "1h", "leverage": 50, "confidence_threshold": 60
High confidence (70%)Only trade when very confident
"confidence_threshold": 70 # Fewer trades, higher conviction
Low threshold (50%)Trade on any edge
"confidence_threshold": 50 # More trades, more noise
Zero commissionNo costs, pure signal test
"commission": 0.0, "swap_long": 0.0, "swap_short": 0.0 # Tests pure signal quality
High commission stressDouble costs, stress test
"commission": 12.0, "swap_long": -2.0, "swap_short": 0.6 # If still profitable, strategy is robust
80/20 splitMore training data
"train_split": 0.8 # 80% train, 20% test
60/40 splitMore validation data
"train_split": 0.6 # 60% train, 40% test: better validation
Short range (1 month)Quick test
"start_date": "2026-03-01", "end_date": "2026-04-01"
Full range (10 months)Maximum data
"start_date": "2025-06-01", "end_date": "2026-04-01"
Long onlyOnly buy positions
"pos_rules": {"max_pos": 1, "direction": "long", "on_opposite": "close_only", "cooldown": 0}Short onlyOnly sell positions
"pos_rules": {"max_pos": 1, "direction": "short", "on_opposite": "close_only", "cooldown": 0}2 positions + cooldownAllow 2 concurrent, 5-bar cooldown
"pos_rules": {"max_pos": 2, "direction": "both", "on_opposite": "reverse", "cooldown": 5}Ignore oppositeStay in trade, ignore reversals
"pos_rules": {"max_pos": 1, "direction": "both", "on_opposite": "ignore", "cooldown": 0} # Stays until stop/TPConservative scalper (full)Complete config combo
{ "capital": 10000, "lot_size": 0.5, "leverage": 50, "confidence_threshold": 60, "commission": 6.0, "timeframe": "5min", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7 }Aggressive trend (full)Complete config combo
{ "capital": 50000, "lot_size": 5.0, "leverage": 200, "confidence_threshold": 55, "commission": 30.0, "timeframe": "1h", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.8 }
API workflows
Generate11
MACD Crossover, BasicSimple MACD crossover strategy with XGBoost
import requests resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "MACD (12,26,9)", "signals": "Buy when MACD crosses above signal line, sell when crosses below", "model": "XGBoost", "optimization": "Maximize Sharpe ratio", "risk": "Stop loss 0.3%", "indicators": {"macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers={"X-API-Key": "qm_YOUR_KEY"}) print(resp.json()["code"][:200])RSI Mean ReversionBuy oversold RSI, sell overbought RSI with Bollinger confirmation
resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "RSI 14, Bollinger Bands (20,2), Volume Z-score", "signals": "Buy when RSI < 30 and price near lower BB, sell when RSI > 70 and price near upper BB", "model": "Random Forest", "optimization": "Maximize Calmar ratio", "risk": "Stop loss 0.5%, max 3 trades per day", "indicators": {"rsi_enabled": true, "rsi_period": 14, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0}, "pos_rules": {"max_pos": 1, "on_opposite": "close_only", "direction": "both", "cooldown": 2}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)EMA Trend Following, Long OnlyLong-only trend strategy using EMA 50/200 golden cross
resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "EMA Cross (50/200), ATR 14", "signals": "Buy when EMA 50 crosses above EMA 200 (golden cross)", "model": "Gradient Boosting", "optimization": "Maximize return", "risk": "Stop loss 0.5%, Kelly position sizing", "indicators": {"ema_enabled": true, "ema_periods": "50,200", "atr_enabled": true, "atr_period": 14}, "pos_rules": {"max_pos": 1, "direction": "long", "on_opposite": "close_only", "cooldown": 3}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)Stochastic + BB ScalperHigh-frequency scalping with Stochastic oversold/overbought + Bollinger breakout
resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "Stochastic (14,3), Bollinger Bands (20,2), RSI 14, ATR 14", "signals": "Buy when Stochastic K < 20 and price below lower BB, sell when K > 80 and price above upper BB", "model": "XGBoost", "optimization": "Maximize win rate", "risk": "Stop loss 0.3%, max 3 trades per day", "indicators": { "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "rsi_enabled": true, "rsi_period": 14, "atr_enabled": true, "atr_period": 14 }, "pos_rules": {"max_pos": 1, "on_opposite": "reverse", "cooldown": 1}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)Multi-Indicator ConservativeConservative strategy combining SMA, RSI, BB with tight drawdown control
resp = requests.post("https://api.quantifyme.ai/api/v1/generate", json={ "features": "SMA (50,200), RSI 14, Bollinger Bands (20,2), ATR 14", "signals": "Buy when price above SMA 200, RSI between 40-60, and close to BB mid", "model": "Logistic Regression", "optimization": "Sharpe > 1 with MDD < 10%", "risk": "Stop loss 0.5%, fixed 1% risk per trade", "indicators": { "sma_enabled": true, "sma_periods": "50,200", "rsi_enabled": true, "rsi_period": 14, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "atr_enabled": true, "atr_period": 14 }, "pos_rules": {"max_pos": 1, "direction": "long", "on_opposite": "close_only", "cooldown": 5}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)MACD with Custom Fast/SlowMACD with non-standard periods (8,21,5) for faster signals
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "MACD (8,21,5), RSI 14", "signals": "MACD crossover: faster periods for quicker entries", "model": "XGBoost", "optimization": "Maximize Sharpe ratio", "risk": "Stop loss 0.3%", "indicators": {"macd_enabled": true, "macd_fast": 8, "macd_slow": 21, "macd_signal": 5, "rsi_enabled": true}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)Short-Only StrategyShort-only RSI overbought strategy with ignore on opposite signals
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "RSI 14, Bollinger Bands (20,2)", "signals": "Short when RSI > 75 and price above upper Bollinger Band", "model": "Random Forest", "optimization": "Maximize win rate", "risk": "Stop loss 0.5%", "indicators": {"rsi_enabled": true, "rsi_period": 14, "bb_enabled": true}, "pos_rules": {"max_pos": 1, "direction": "short", "on_opposite": "ignore", "cooldown": 3}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)Session-Filtered StrategyOnly trade during London-NY overlap with risk filter
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "MACD (12,26,9), ATR 14, Volume Z-score", "signals": "MACD crossover with volume confirmation", "model": "XGBoost", "optimization": "Maximize Sharpe ratio", "risk": "Stop loss 0.3%, fixed 1% risk per trade", "risk_function": "Only trade during London-NY overlap (13:00-17:00 UTC). No trading on Fridays after 18:00 UTC. Skip if ATR is below its 20-bar average.", "indicators": {"macd_enabled": true, "atr_enabled": true, "atr_period": 14}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)ATR-Based Position SizingUse ATR to dynamically size positions, wider stops when volatile
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "EMA Cross (50/200), ATR 14, RSI 14", "signals": "MA crossover with RSI between 40-60 as filter", "model": "Gradient Boosting", "optimization": "Minimize max drawdown", "risk": "ATR-based stop loss: stop = 2 x ATR(14). Position size = 1% account risk / stop distance. Scale down when ATR > 1.5x its 20-bar average.", "indicators": {"ema_enabled": true, "ema_periods": "50,200", "atr_enabled": true, "atr_period": 14, "rsi_enabled": true}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)WMA + Stochastic ComboWeighted Moving Average trend + Stochastic timing
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "WMA 20, Stochastic (14,3), ATR 14", "signals": "Buy when price above WMA and Stochastic crosses above 20 from below. Sell when price below WMA and Stochastic crosses below 80 from above.", "model": "XGBoost", "optimization": "Maximize Sharpe ratio", "risk": "Stop loss 0.4%", "indicators": {"wma_enabled": true, "wma_periods": "20", "stoch_enabled": true, "stoch_k": 14, "stoch_d": 3, "atr_enabled": true}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)Max 2 Positions + CooldownAllow 2 concurrent positions with 5-bar cooldown between trades
resp = requests.post(f"{BASE}/api/v1/generate", json={ "features": "MACD (12,26,9), RSI 14, Bollinger Bands (20,2)", "signals": "MACD crossover confirmed by RSI", "model": "XGBoost", "optimization": "Maximize return", "risk": "Stop loss 0.3% per position", "indicators": {"macd_enabled": true, "rsi_enabled": true, "bb_enabled": true}, "pos_rules": {"max_pos": 2, "on_opposite": "reverse", "direction": "both", "cooldown": 5}, "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS)
Templates3
MACD MomentumUse the built-in MACD Momentum template with no customization
resp = requests.post("https://api.quantifyme.ai/api/v1/generate/from-template", json={ "template": "macd_momentum", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS) print(resp.json()["template_name"]) # "MACD Momentum"Scalper, Long Only OverrideUse scalper template but override to long-only with custom RSI period
resp = requests.post("https://api.quantifyme.ai/api/v1/generate/from-template", json={ "template": "scalper", "start_date": "2025-06-01", "end_date": "2026-04-01", "pos_rules": {"direction": "long"}, "indicators": {"rsi_period": 21}, "claude_model": "sonnet" }, headers=HEADERS) # Template indicators (stoch, bb, rsi, atr) preserved # RSI period overridden from 14 to 21 # Direction overridden to long-onlyMean Reversion + Custom RiskMean reversion template with custom risk filter for session hours
resp = requests.post("https://api.quantifyme.ai/api/v1/generate/from-template", json={ "template": "mean_reversion", "start_date": "2025-06-01", "end_date": "2026-04-01", "risk_function": "Only trade during London-NY overlap (13:00-17:00 UTC), skip Fridays after 18:00", "claude_model": "sonnet" }, headers=HEADERS)
Train1
Train Model from Generated CodeGenerate strategy, then submit for training and poll until done
import time # Step 1: Generate gen = requests.post(f"{BASE}/api/v1/generate", json={ "features": "MACD, RSI 14", "signals": "MACD crossover with RSI confirmation", "model": "XGBoost", "optimization": "Maximize Sharpe", "risk": "Stop loss 0.3%", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "claude_model": "sonnet" }, headers=HEADERS) code = gen.json()["code"] # Step 2: Train train = requests.post(f"{BASE}/api/v1/train", json={ "code": code, "model_name": "My MACD Model", "start_date": "2025-06-01", "end_date": "2026-04-01", "train_split": 0.7, "timeframe": "15min" }, headers=HEADERS) job_id = train.json()["job_id"] # Step 3: Poll while True: s = requests.get(f"{BASE}/api/v1/train/{job_id}", headers=HEADERS).json() print(s["status"]) if s["status"] in ("done", "failed"): break time.sleep(3) if s["status"] == "done": print(s["metrics"])
Indicators3
Compute RSI ValuesGet RSI 14 values for last 100 bars without training
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators", json={ "indicators": {"rsi_enabled": true, "rsi_period": 14}, "symbol": "EURUSD", "timeframe": "15min", "limit": 100, "format": "columns" }, headers=HEADERS) data = resp.json() print(data["ind_rsi14"][:5]) # [45.2, 48.1, 52.3, ...] print(data["timestamps"][:5]) # ["2026-04-13 22:00:00", ...]Compute MACD + BB + ATRGet multiple indicators at once in row format
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators", json={ "indicators": { "macd_enabled": true, "macd_fast": 12, "macd_slow": 26, "macd_signal": 9, "bb_enabled": true, "bb_period": 20, "bb_std": 2.0, "atr_enabled": true, "atr_period": 14 }, "symbol": "EURUSD", "timeframe": "1h", "start": "2026-04-01", "limit": 50, "format": "rows" }, headers=HEADERS) for row in resp.json()["data"][:3]: print(row["timestamp"], row["ind_macd_line"], row["ind_bb_pct"])Compute SMA Distance from PriceSMA 20/50/200 with distance-from-price features
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators", json={ "indicators": {"sma_enabled": true, "sma_periods": "20,50,200"}, "timeframe": "15min", "limit": 200 }, headers=HEADERS) data = resp.json() # data["ind_sma20"]: raw SMA 20 values # data["ind_dm_sma20"]: distance: (close - sma20) / sma20 # data["ind_sma50"], data["ind_dm_sma50"], etc. print(f"Indicators computed: {data['meta']['indicators_computed']}")
Custom indicator3
SupertrendGenerate a Supertrend indicator from natural language
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators/custom", json={ "source": "Supertrend indicator with ATR period 10 and multiplier 3. Show buy/sell signals on crossover.", "symbol": "EURUSD", "timeframe": "15min", "limit": 2000, "provider": "anthropic", "fe_mode": "basic" }, headers=HEADERS) result = resp.json() print(f"Name: {result['name']}") print(f"Overlays: {len(result['overlays'])}") print(f"Signals: {len(result['signals'])}") print(f"Features: {list(result['features'].keys())}")Hull MAHull Moving Average with trend coloring
resp = requests.post("https://api.quantifyme.ai/api/v1/indicators/custom", json={ "source": "Hull Moving Average (HMA) with period 20. Color green when rising, red when falling. Generate buy signal when HMA turns from falling to rising, sell when turns from rising to falling.", "timeframe": "15min", "fe_mode": "full" }, headers=HEADERS) result = resp.json() print(f"{result['name']}: {len(result['signals'])} signals") print(f"ML features: {len(result['features'])} columns")Pine Script RSI DivergenceConvert Pine Script RSI divergence detector to Python
pine_code = """ //@version=5 indicator('RSI Divergence', overlay=false) rsi_len = input(14) rsi_val = ta.rsi(close, rsi_len) bull_div = rsi_val < 30 and rsi_val > rsi_val[5] and close < close[5] bear_div = rsi_val > 70 and rsi_val < rsi_val[5] and close > close[5] plot(rsi_val) plotshape(bull_div, style=shape.triangleup, location=location.bottom) plotshape(bear_div, style=shape.triangledown, location=location.top) """ resp = requests.post("https://api.quantifyme.ai/api/v1/indicators/custom", json={ "source": pine_code, "timeframe": "15min", "fe_mode": "basic" }, headers=HEADERS)
Discovery2
Discover Available PresetsList all chip presets, templates, and position rules options
# No auth needed for discovery endpoints presets = requests.get(f"{BASE}/api/v1/presets").json() print("Feature chips:", presets["chips"]["features"]) print("Signal chips:", presets["chips"]["signals"]) print("Model chips:", presets["chips"]["model"]) print() print("Templates:") for key, t in presets["templates"].items(): print(f" {key}: {t['name']}: {t['description']}") print() print("Position rules:") for k, v in presets["pos_rules_schema"].items(): print(f" {k}: options={v.get('options','any')}, default={v['default']}")Discover Indicator SchemaList all available indicators with params and defaults
schema = requests.get(f"{BASE}/api/v1/indicator-schema").json() for name, ind in schema["indicators"].items(): params = ", ".join(f"{k}={v['default']}" for k, v in ind["params"].items()) features = ", ".join(ind["features_generated"]) print(f"{name:8} | {ind['description'][:50]:50} | {params}") print(f"{'':8} | features: {features}")
Data1
Get OHLC DataFetch raw OHLC candle data for analysis
resp = requests.get(f"{BASE}/api/v1/ohlc", params={ "symbol": "EURUSD", "timeframe": "15min", "start": "2026-04-01", "limit": 100 }, headers=HEADERS) data = resp.json() print(f"{data['rows']} rows, {data['tokens_remaining']} tokens left") for bar in data["data"][:3]: print(f"{bar['time']} O={bar['open']:.5f} H={bar['high']:.5f} L={bar['low']:.5f} C={bar['close']:.5f}")
Models1
List All Trained ModelsFetch all your trained models with metadata
resp = requests.get(f"{BASE}/api/v1/models", headers=HEADERS) for m in resp.json()["models"]: print(f"{m['model_name']:20} trained: {m.get('train_start','')} → {m.get('train_end','')}")