> ## Documentation Index
> Fetch the complete documentation index at: https://docs.innova-trading.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Complete Examples

> Copy-paste ready scripts - Full indicators from start to finish

This page contains **complete scripts** you can copy, paste, and run directly. Each example is a fully functional indicator from start to finish.

## Example 1: Swing Points Detector (HH/HL/LH/LL)

Detects Higher Highs, Higher Lows, Lower Highs, and Lower Lows - the foundation of market structure analysis.

> [tab] Python
>
> ```python theme={null}
> #!/usr/bin/env python3
> """
> Swing Points Detector - InnovaTrading External Indicator
> Detects HH, HL, LH, LL on chart
> """
>
> import requests
> import pandas as pd
> from typing import List, Dict, Any
>
> # === CONFIGURATION ===
> API_KEY = "YOUR_API_KEY"
> BASE_URL = "https://api.innova-trading.com"
> SYMBOL = "EURUSD"
> TIMEFRAME = 60  # H1
> SWING_LOOKBACK = 5  # Bars on each side to confirm swing
>
> # === API CLIENT ===
> def get_bars(symbol: str, timeframe: int, limit: int = 500) -> pd.DataFrame:
>     url = f"{BASE_URL}/api/external/bars/{symbol}/{timeframe}"
>     headers = {"Authorization": f"Bearer {API_KEY}"}
>     response = requests.get(url, params={"limit": limit}, headers=headers)
>     response.raise_for_status()
>     return pd.DataFrame(response.json()["bars"])
>
> def submit_indicator(indicator_id: str, points: List[Dict], symbol: str, timeframe: int):
>     url = f"{BASE_URL}/api/external/indicators/{indicator_id}"
>     headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
>     payload = {
>         "symbol": symbol,
>         "timeframe": timeframe,
>         "indicator_name": "Swing Points (HH/HL/LH/LL)",
>         "version": "1.0",
>         "points": points,
>         "metadata": {"lookback": SWING_LOOKBACK, "total_swings": len(points)}
>     }
>     response = requests.post(url, json=payload, headers=headers)
>     response.raise_for_status()
>     return response.json()
>
> # === INDICATOR LOGIC ===
> def is_swing_high(df: pd.DataFrame, index: int, lookback: int) -> bool:
>     """Check if index is a swing high."""
>     if index < lookback or index >= len(df) - lookback:
>         return False
>
>     current_high = df.iloc[index]["high"]
>     for i in range(index - lookback, index + lookback + 1):
>         if i != index and df.iloc[i]["high"] >= current_high:
>             return False
>     return True
>
> def is_swing_low(df: pd.DataFrame, index: int, lookback: int) -> bool:
>     """Check if index is a swing low."""
>     if index < lookback or index >= len(df) - lookback:
>         return False
>
>     current_low = df.iloc[index]["low"]
>     for i in range(index - lookback, index + lookback + 1):
>         if i != index and df.iloc[i]["low"] <= current_low:
>             return False
>     return True
>
> def detect_swing_points(df: pd.DataFrame) -> List[Dict[str, Any]]:
>     """Detect swing points and classify as HH/HL/LH/LL."""
>     points = []
>
>     # Find all swings
>     swing_highs = []
>     swing_lows = []
>
>     for i in range(len(df)):
>         if is_swing_high(df, i, SWING_LOOKBACK):
>             swing_highs.append({"index": i, "price": df.iloc[i]["high"], "time": df.iloc[i]["time"]})
>         if is_swing_low(df, i, SWING_LOOKBACK):
>             swing_lows.append({"index": i, "price": df.iloc[i]["low"], "time": df.iloc[i]["time"]})
>
>     # Classify Swing Highs as HH or LH
>     for i, sh in enumerate(swing_highs):
>         if i == 0:
>             label = "SH"  # First swing, no comparison
>             color = "#94a3b8"
>         else:
>             prev_high = swing_highs[i-1]["price"]
>             if sh["price"] > prev_high:
>                 label = "HH"  # Higher High
>                 color = "#22c55e"  # Green
>             else:
>                 label = "LH"  # Lower High
>                 color = "#ef4444"  # Red
>
>         points.append({
>             "time": int(sh["time"]),
>             "type": "high",
>             "price": float(sh["price"]),
>             "label": label,
>             "color": color,
>             "shape": "circle",
>             "size": 1 if label == "SH" else 2
>         })
>
>     # Classify Swing Lows as HL or LL
>     for i, sl in enumerate(swing_lows):
>         if i == 0:
>             label = "SL"  # First swing, no comparison
>             color = "#94a3b8"
>         else:
>             prev_low = swing_lows[i-1]["price"]
>             if sl["price"] > prev_low:
>                 label = "HL"  # Higher Low
>                 color = "#22c55e"  # Green
>             else:
>                 label = "LL"  # Lower Low
>                 color = "#ef4444"  # Red
>
>         points.append({
>             "time": int(sl["time"]),
>             "type": "low",
>             "price": float(sl["price"]),
>             "label": label,
>             "color": color,
>             "shape": "circle",
>             "size": 1 if label == "SL" else 2
>         })
>
>     return points
>
> # === MAIN ===
> def main():
>     print("=" * 50)
>     print("Swing Points Detector")
>     print("=" * 50)
>
>     print(f"\n1. Fetching {SYMBOL} {TIMEFRAME}m bars...")
>     df = get_bars(SYMBOL, TIMEFRAME, 500)
>     print(f"   Got {len(df)} bars")
>
>     print("\n2. Detecting swing points...")
>     points = detect_swing_points(df)
>
>     # Count types
>     hh = sum(1 for p in points if p["label"] == "HH")
>     hl = sum(1 for p in points if p["label"] == "HL")
>     lh = sum(1 for p in points if p["label"] == "LH")
>     ll = sum(1 for p in points if p["label"] == "LL")
>
>     print(f"   HH: {hh}, HL: {hl}, LH: {lh}, LL: {ll}")
>
>     print("\n3. Submitting to InnovaTrading...")
>     result = submit_indicator("swing_points", points, SYMBOL, TIMEFRAME)
>     print(f"   Submitted {result['points_received']} points")
>     print(f"   Expires: {result['expires_at']}")
>
>     print("\n" + "=" * 50)
>     print("Done! Check the chart.")
>     print("=" * 50)
>
> if __name__ == "__main__":
>     main()
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> /**
>  * Swing Points Detector - InnovaTrading External Indicator
>  * Detects HH, HL, LH, LL on chart
>  */
>
> const axios = require("axios");
>
> // === CONFIGURATION ===
> const API_KEY = "YOUR_API_KEY";
> const BASE_URL = "https://api.innova-trading.com";
> const SYMBOL = "EURUSD";
> const TIMEFRAME = 60; // H1
> const SWING_LOOKBACK = 5;
>
> // === API CLIENT ===
> async function getBars(symbol, timeframe, limit = 500) {
>   const response = await axios.get(
>     `${BASE_URL}/api/external/bars/${symbol}/${timeframe}`,
>     {
>       params: { limit },
>       headers: { Authorization: `Bearer ${API_KEY}` },
>     }
>   );
>   return response.data.bars;
> }
>
> async function submitIndicator(indicatorId, points, symbol, timeframe) {
>   const response = await axios.post(
>     `${BASE_URL}/api/external/indicators/${indicatorId}`,
>     {
>       symbol,
>       timeframe,
>       indicator_name: "Swing Points (HH/HL/LH/LL)",
>       version: "1.0",
>       points,
>       metadata: { lookback: SWING_LOOKBACK, total_swings: points.length },
>     },
>     {
>       headers: {
>         Authorization: `Bearer ${API_KEY}`,
>         "Content-Type": "application/json",
>       },
>     }
>   );
>   return response.data;
> }
>
> // === INDICATOR LOGIC ===
> function isSwingHigh(bars, index, lookback) {
>   if (index < lookback || index >= bars.length - lookback) return false;
>
>   const currentHigh = bars[index].high;
>   for (let i = index - lookback; i <= index + lookback; i++) {
>     if (i !== index && bars[i].high >= currentHigh) return false;
>   }
>   return true;
> }
>
> function isSwingLow(bars, index, lookback) {
>   if (index < lookback || index >= bars.length - lookback) return false;
>
>   const currentLow = bars[index].low;
>   for (let i = index - lookback; i <= index + lookback; i++) {
>     if (i !== index && bars[i].low <= currentLow) return false;
>   }
>   return true;
> }
>
> function detectSwingPoints(bars) {
>   const points = [];
>   const swingHighs = [];
>   const swingLows = [];
>
>   // Find all swings
>   for (let i = 0; i < bars.length; i++) {
>     if (isSwingHigh(bars, i, SWING_LOOKBACK)) {
>       swingHighs.push({
>         index: i,
>         price: bars[i].high,
>         time: bars[i].time,
>       });
>     }
>     if (isSwingLow(bars, i, SWING_LOOKBACK)) {
>       swingLows.push({
>         index: i,
>         price: bars[i].low,
>         time: bars[i].time,
>       });
>     }
>   }
>
>   // Classify Swing Highs
>   swingHighs.forEach((sh, i) => {
>     let label, color;
>     if (i === 0) {
>       label = "SH";
>       color = "#94a3b8";
>     } else {
>       const prevHigh = swingHighs[i - 1].price;
>       if (sh.price > prevHigh) {
>         label = "HH";
>         color = "#22c55e";
>       } else {
>         label = "LH";
>         color = "#ef4444";
>       }
>     }
>
>     points.push({
>       time: sh.time,
>       type: "high",
>       price: sh.price,
>       label,
>       color,
>       shape: "circle",
>       size: label === "SH" ? 1 : 2,
>     });
>   });
>
>   // Classify Swing Lows
>   swingLows.forEach((sl, i) => {
>     let label, color;
>     if (i === 0) {
>       label = "SL";
>       color = "#94a3b8";
>     } else {
>       const prevLow = swingLows[i - 1].price;
>       if (sl.price > prevLow) {
>         label = "HL";
>         color = "#22c55e";
>       } else {
>         label = "LL";
>         color = "#ef4444";
>       }
>     }
>
>     points.push({
>       time: sl.time,
>       type: "low",
>       price: sl.price,
>       label,
>       color,
>       shape: "circle",
>       size: label === "SL" ? 1 : 2,
>     });
>   });
>
>   return points;
> }
>
> // === MAIN ===
> async function main() {
>   console.log("=".repeat(50));
>   console.log("Swing Points Detector");
>   console.log("=".repeat(50));
>
>   console.log(`\n1. Fetching ${SYMBOL} ${TIMEFRAME}m bars...`);
>   const bars = await getBars(SYMBOL, TIMEFRAME, 500);
>   console.log(`   Got ${bars.length} bars`);
>
>   console.log("\n2. Detecting swing points...");
>   const points = detectSwingPoints(bars);
>
>   const hh = points.filter((p) => p.label === "HH").length;
>   const hl = points.filter((p) => p.label === "HL").length;
>   const lh = points.filter((p) => p.label === "LH").length;
>   const ll = points.filter((p) => p.label === "LL").length;
>
>   console.log(`   HH: ${hh}, HL: ${hl}, LH: ${lh}, LL: ${ll}`);
>
>   console.log("\n3. Submitting to InnovaTrading...");
>   const result = await submitIndicator("swing_points", points, SYMBOL, TIMEFRAME);
>   console.log(`   Submitted ${result.points_received} points`);
>   console.log(`   Expires: ${result.expires_at}`);
>
>   console.log("\n" + "=".repeat(50));
>   console.log("Done! Check the chart.");
>   console.log("=".repeat(50));
> }
>
> main().catch(console.error);
> ```

***

## Example 2: RSI with Overbought/Oversold Zones

Calculates RSI and marks overbought (>70) and oversold (\<30) zones.

> [tab] Python
>
> ```python theme={null}
> #!/usr/bin/env python3
> """
> RSI Indicator - InnovaTrading External Indicator
> Marks overbought and oversold zones
> """
>
> import requests
> import pandas as pd
> from typing import List, Dict, Any
>
> # === CONFIGURATION ===
> API_KEY = "YOUR_API_KEY"
> BASE_URL = "https://api.innova-trading.com"
> SYMBOL = "EURUSD"
> TIMEFRAME = 60
> RSI_PERIOD = 14
> RSI_OVERBOUGHT = 70
> RSI_OVERSOLD = 30
>
> def get_bars(symbol: str, timeframe: int, limit: int = 500) -> pd.DataFrame:
>     url = f"{BASE_URL}/api/external/bars/{symbol}/{timeframe}"
>     headers = {"Authorization": f"Bearer {API_KEY}"}
>     response = requests.get(url, params={"limit": limit}, headers=headers)
>     response.raise_for_status()
>     return pd.DataFrame(response.json()["bars"])
>
> def submit_indicator(indicator_id: str, points: List[Dict], symbol: str, timeframe: int, metadata: Dict = None):
>     url = f"{BASE_URL}/api/external/indicators/{indicator_id}"
>     headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
>     payload = {
>         "symbol": symbol,
>         "timeframe": timeframe,
>         "indicator_name": f"RSI({RSI_PERIOD}) Signals",
>         "version": "1.0",
>         "points": points,
>         "metadata": metadata or {}
>     }
>     response = requests.post(url, json=payload, headers=headers)
>     response.raise_for_status()
>     return response.json()
>
> def calculate_rsi(df: pd.DataFrame, period: int = 14) -> pd.Series:
>     """Calculate RSI using Wilder's method."""
>     delta = df["close"].diff()
>
>     gain = delta.where(delta > 0, 0)
>     loss = (-delta).where(delta < 0, 0)
>
>     avg_gain = gain.ewm(alpha=1/period, min_periods=period).mean()
>     avg_loss = loss.ewm(alpha=1/period, min_periods=period).mean()
>
>     rs = avg_gain / avg_loss
>     rsi = 100 - (100 / (1 + rs))
>
>     return rsi
>
> def detect_rsi_signals(df: pd.DataFrame) -> List[Dict[str, Any]]:
>     """Detect RSI crosses at extreme zones."""
>     df["rsi"] = calculate_rsi(df, RSI_PERIOD)
>     points = []
>
>     for i in range(1, len(df)):
>         prev_rsi = df.iloc[i-1]["rsi"]
>         curr_rsi = df.iloc[i]["rsi"]
>         curr = df.iloc[i]
>
>         if pd.isna(prev_rsi) or pd.isna(curr_rsi):
>             continue
>
>         # RSI crosses down from overbought (sell signal)
>         if prev_rsi >= RSI_OVERBOUGHT and curr_rsi < RSI_OVERBOUGHT:
>             points.append({
>                 "time": int(curr["time"]),
>                 "type": "high",
>                 "price": float(curr["high"]) + 0.0003,
>                 "label": f"OB",
>                 "color": "#ef4444",
>                 "shape": "arrowDown",
>                 "size": 2
>             })
>
>         # RSI crosses up from oversold (buy signal)
>         if prev_rsi <= RSI_OVERSOLD and curr_rsi > RSI_OVERSOLD:
>             points.append({
>                 "time": int(curr["time"]),
>                 "type": "low",
>                 "price": float(curr["low"]) - 0.0003,
>                 "label": f"OS",
>                 "color": "#22c55e",
>                 "shape": "arrowUp",
>                 "size": 2
>             })
>
>     return points
>
> def main():
>     print("=" * 50)
>     print(f"RSI({RSI_PERIOD}) Indicator")
>     print("=" * 50)
>
>     print(f"\n1. Fetching {SYMBOL} {TIMEFRAME}m bars...")
>     df = get_bars(SYMBOL, TIMEFRAME, 500)
>     print(f"   Got {len(df)} bars")
>
>     print("\n2. Calculating RSI and detecting signals...")
>     points = detect_rsi_signals(df)
>
>     ob_count = sum(1 for p in points if p["label"] == "OB")
>     os_count = sum(1 for p in points if p["label"] == "OS")
>
>     print(f"   Overbought (OB): {ob_count}")
>     print(f"   Oversold (OS): {os_count}")
>
>     if points:
>         print("\n3. Submitting to InnovaTrading...")
>         result = submit_indicator(
>             "rsi_signals",
>             points,
>             SYMBOL,
>             TIMEFRAME,
>             {
>                 "rsi_period": RSI_PERIOD,
>                 "overbought": RSI_OVERBOUGHT,
>                 "oversold": RSI_OVERSOLD,
>                 "ob_signals": ob_count,
>                 "os_signals": os_count
>             }
>         )
>         print(f"   Submitted {result['points_received']} points")
>     else:
>         print("\n   No RSI signals found")
>
>     print("\n" + "=" * 50)
>
> if __name__ == "__main__":
>     main()
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> /**
>  * RSI Indicator - InnovaTrading External Indicator
>  * Marks overbought and oversold zones
>  */
>
> const axios = require("axios");
>
> // === CONFIGURATION ===
> const API_KEY = "YOUR_API_KEY";
> const BASE_URL = "https://api.innova-trading.com";
> const SYMBOL = "EURUSD";
> const TIMEFRAME = 60;
> const RSI_PERIOD = 14;
> const RSI_OVERBOUGHT = 70;
> const RSI_OVERSOLD = 30;
>
> async function getBars(symbol, timeframe, limit = 500) {
>   const response = await axios.get(
>     `${BASE_URL}/api/external/bars/${symbol}/${timeframe}`,
>     {
>       params: { limit },
>       headers: { Authorization: `Bearer ${API_KEY}` },
>     }
>   );
>   return response.data.bars;
> }
>
> async function submitIndicator(indicatorId, points, symbol, timeframe, metadata = {}) {
>   const response = await axios.post(
>     `${BASE_URL}/api/external/indicators/${indicatorId}`,
>     {
>       symbol,
>       timeframe,
>       indicator_name: `RSI(${RSI_PERIOD}) Signals`,
>       version: "1.0",
>       points,
>       metadata,
>     },
>     {
>       headers: {
>         Authorization: `Bearer ${API_KEY}`,
>         "Content-Type": "application/json",
>       },
>     }
>   );
>   return response.data;
> }
>
> function calculateRSI(bars, period = 14) {
>   const closes = bars.map((b) => b.close);
>   const rsi = new Array(closes.length).fill(null);
>
>   const changes = [];
>   for (let i = 1; i < closes.length; i++) {
>     changes.push(closes[i] - closes[i - 1]);
>   }
>
>   let avgGain = 0;
>   let avgLoss = 0;
>
>   for (let i = 0; i < period; i++) {
>     if (changes[i] > 0) avgGain += changes[i];
>     else avgLoss += Math.abs(changes[i]);
>   }
>
>   avgGain /= period;
>   avgLoss /= period;
>
>   if (avgLoss === 0) {
>     rsi[period] = 100;
>   } else {
>     const rs = avgGain / avgLoss;
>     rsi[period] = 100 - 100 / (1 + rs);
>   }
>
>   for (let i = period; i < changes.length; i++) {
>     const change = changes[i];
>     const gain = change > 0 ? change : 0;
>     const loss = change < 0 ? Math.abs(change) : 0;
>
>     avgGain = (avgGain * (period - 1) + gain) / period;
>     avgLoss = (avgLoss * (period - 1) + loss) / period;
>
>     if (avgLoss === 0) {
>       rsi[i + 1] = 100;
>     } else {
>       const rs = avgGain / avgLoss;
>       rsi[i + 1] = 100 - 100 / (1 + rs);
>     }
>   }
>
>   return rsi;
> }
>
> function detectRSISignals(bars) {
>   const rsi = calculateRSI(bars, RSI_PERIOD);
>   const points = [];
>
>   for (let i = 1; i < bars.length; i++) {
>     const prevRsi = rsi[i - 1];
>     const currRsi = rsi[i];
>
>     if (prevRsi === null || currRsi === null) continue;
>
>     if (prevRsi >= RSI_OVERBOUGHT && currRsi < RSI_OVERBOUGHT) {
>       points.push({
>         time: bars[i].time,
>         type: "high",
>         price: bars[i].high + 0.0003,
>         label: "OB",
>         color: "#ef4444",
>         shape: "arrowDown",
>         size: 2,
>       });
>     }
>
>     if (prevRsi <= RSI_OVERSOLD && currRsi > RSI_OVERSOLD) {
>       points.push({
>         time: bars[i].time,
>         type: "low",
>         price: bars[i].low - 0.0003,
>         label: "OS",
>         color: "#22c55e",
>         shape: "arrowUp",
>         size: 2,
>       });
>     }
>   }
>
>   return points;
> }
>
> async function main() {
>   console.log("=".repeat(50));
>   console.log(`RSI(${RSI_PERIOD}) Indicator`);
>   console.log("=".repeat(50));
>
>   console.log(`\n1. Fetching ${SYMBOL} ${TIMEFRAME}m bars...`);
>   const bars = await getBars(SYMBOL, TIMEFRAME, 500);
>   console.log(`   Got ${bars.length} bars`);
>
>   console.log("\n2. Calculating RSI and detecting signals...");
>   const points = detectRSISignals(bars);
>
>   const obCount = points.filter((p) => p.label === "OB").length;
>   const osCount = points.filter((p) => p.label === "OS").length;
>
>   console.log(`   Overbought (OB): ${obCount}`);
>   console.log(`   Oversold (OS): ${osCount}`);
>
>   if (points.length > 0) {
>     console.log("\n3. Submitting to InnovaTrading...");
>     const result = await submitIndicator("rsi_signals", points, SYMBOL, TIMEFRAME, {
>       rsi_period: RSI_PERIOD,
>       overbought: RSI_OVERBOUGHT,
>       oversold: RSI_OVERSOLD,
>       ob_signals: obCount,
>       os_signals: osCount,
>     });
>     console.log(`   Submitted ${result.points_received} points`);
>   } else {
>     console.log("\n   No RSI signals found");
>   }
>
>   console.log("\n" + "=".repeat(50));
> }
>
> main().catch(console.error);
> ```

***

## Example 3: Complete Trade Signal Generator

Generates BUY/SELL signals with Entry, Stop Loss, and multiple Take Profits.

> [tab] Python
>
> ```python theme={null}
> #!/usr/bin/env python3
> """
> Complete Trade Signal Generator
> Entry + SL + TP1 + TP2 + TP3
> """
>
> import requests
> import pandas as pd
> from typing import List, Dict, Any
>
> # === CONFIGURATION ===
> API_KEY = "YOUR_API_KEY"
> BASE_URL = "https://api.innova-trading.com"
> SYMBOL = "EURUSD"
> TIMEFRAME = 60
>
> # Trading parameters
> ATR_PERIOD = 14
> SL_ATR_MULTIPLIER = 1.5
> TP1_ATR_MULTIPLIER = 1.5  # 1:1
> TP2_ATR_MULTIPLIER = 3.0  # 1:2
> TP3_ATR_MULTIPLIER = 4.5  # 1:3
>
> def get_bars(symbol: str, timeframe: int, limit: int = 500) -> pd.DataFrame:
>     url = f"{BASE_URL}/api/external/bars/{symbol}/{timeframe}"
>     headers = {"Authorization": f"Bearer {API_KEY}"}
>     response = requests.get(url, params={"limit": limit}, headers=headers)
>     response.raise_for_status()
>     return pd.DataFrame(response.json()["bars"])
>
> def submit_indicator(indicator_id: str, points: List[Dict], symbol: str, timeframe: int, metadata: Dict = None):
>     url = f"{BASE_URL}/api/external/indicators/{indicator_id}"
>     headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
>     payload = {
>         "symbol": symbol,
>         "timeframe": timeframe,
>         "indicator_name": "Trade Signals (Entry + SL + TPs)",
>         "version": "1.0",
>         "points": points,
>         "metadata": metadata or {}
>     }
>     response = requests.post(url, json=payload, headers=headers)
>     response.raise_for_status()
>     return response.json()
>
> def calculate_atr(df: pd.DataFrame, period: int = 14) -> pd.Series:
>     """Calculate Average True Range."""
>     high = df["high"]
>     low = df["low"]
>     close = df["close"].shift(1)
>
>     tr1 = high - low
>     tr2 = abs(high - close)
>     tr3 = abs(low - close)
>
>     tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
>     atr = tr.rolling(window=period).mean()
>
>     return atr
>
> def detect_bullish_setup(df: pd.DataFrame, index: int) -> bool:
>     """Detect simple bullish setup (3 consecutive bullish candles)."""
>     if index < 3:
>         return False
>
>     for i in range(index - 2, index + 1):
>         if df.iloc[i]["close"] <= df.iloc[i]["open"]:
>             return False
>
>     return True
>
> def detect_bearish_setup(df: pd.DataFrame, index: int) -> bool:
>     """Detect simple bearish setup (3 consecutive bearish candles)."""
>     if index < 3:
>         return False
>
>     for i in range(index - 2, index + 1):
>         if df.iloc[i]["close"] >= df.iloc[i]["open"]:
>             return False
>
>     return True
>
> def generate_trade_signals(df: pd.DataFrame) -> List[Dict[str, Any]]:
>     """Generate complete trade signals."""
>     df["atr"] = calculate_atr(df, ATR_PERIOD)
>     points = []
>
>     for i in range(max(ATR_PERIOD, 3), len(df)):
>         curr = df.iloc[i]
>         atr = curr["atr"]
>
>         if pd.isna(atr):
>             continue
>
>         bar_time = int(curr["time"])
>
>         # Bullish setup
>         if detect_bullish_setup(df, i):
>             entry = float(curr["close"])
>             sl = entry - (atr * SL_ATR_MULTIPLIER)
>             tp1 = entry + (atr * TP1_ATR_MULTIPLIER)
>             tp2 = entry + (atr * TP2_ATR_MULTIPLIER)
>             tp3 = entry + (atr * TP3_ATR_MULTIPLIER)
>
>             # Entry point
>             points.append({
>                 "time": bar_time,
>                 "type": "low",
>                 "price": entry,
>                 "label": "BUY",
>                 "color": "#3b82f6",
>                 "shape": "arrowUp",
>                 "size": 2
>             })
>
>             # Stop Loss
>             points.append({
>                 "time": bar_time,
>                 "type": "low",
>                 "price": sl,
>                 "label": "SL",
>                 "color": "#ef4444",
>                 "shape": "square",
>                 "size": 1
>             })
>
>             # Take Profits
>             for tp_num, tp_price in enumerate([tp1, tp2, tp3], 1):
>                 points.append({
>                     "time": bar_time,
>                     "type": "high",
>                     "price": tp_price,
>                     "label": f"TP{tp_num}",
>                     "color": "#22c55e",
>                     "shape": "circle",
>                     "size": 1
>                 })
>
>         # Bearish setup
>         elif detect_bearish_setup(df, i):
>             entry = float(curr["close"])
>             sl = entry + (atr * SL_ATR_MULTIPLIER)
>             tp1 = entry - (atr * TP1_ATR_MULTIPLIER)
>             tp2 = entry - (atr * TP2_ATR_MULTIPLIER)
>             tp3 = entry - (atr * TP3_ATR_MULTIPLIER)
>
>             # Entry point
>             points.append({
>                 "time": bar_time,
>                 "type": "high",
>                 "price": entry,
>                 "label": "SELL",
>                 "color": "#f97316",
>                 "shape": "arrowDown",
>                 "size": 2
>             })
>
>             # Stop Loss
>             points.append({
>                 "time": bar_time,
>                 "type": "high",
>                 "price": sl,
>                 "label": "SL",
>                 "color": "#ef4444",
>                 "shape": "square",
>                 "size": 1
>             })
>
>             # Take Profits
>             for tp_num, tp_price in enumerate([tp1, tp2, tp3], 1):
>                 points.append({
>                     "time": bar_time,
>                     "type": "low",
>                     "price": tp_price,
>                     "label": f"TP{tp_num}",
>                     "color": "#22c55e",
>                     "shape": "circle",
>                     "size": 1
>                 })
>
>     return points
>
> def main():
>     print("=" * 50)
>     print("Complete Trade Signal Generator")
>     print("=" * 50)
>
>     print(f"\n1. Fetching {SYMBOL} {TIMEFRAME}m bars...")
>     df = get_bars(SYMBOL, TIMEFRAME, 200)
>     print(f"   Got {len(df)} bars")
>
>     print("\n2. Generating trade signals...")
>     points = generate_trade_signals(df)
>
>     buys = sum(1 for p in points if p["label"] == "BUY")
>     sells = sum(1 for p in points if p["label"] == "SELL")
>
>     print(f"   BUY signals: {buys}")
>     print(f"   SELL signals: {sells}")
>     print(f"   Total points: {len(points)}")
>
>     if points:
>         print("\n3. Submitting to InnovaTrading...")
>         result = submit_indicator(
>             "trade_signals",
>             points,
>             SYMBOL,
>             TIMEFRAME,
>             {
>                 "atr_period": ATR_PERIOD,
>                 "sl_multiplier": SL_ATR_MULTIPLIER,
>                 "tp_multipliers": [TP1_ATR_MULTIPLIER, TP2_ATR_MULTIPLIER, TP3_ATR_MULTIPLIER],
>                 "buys": buys,
>                 "sells": sells
>             }
>         )
>         print(f"   Submitted {result['points_received']} points")
>         print(f"   Expires: {result['expires_at']}")
>     else:
>         print("\n   No trade setups found")
>
>     print("\n" + "=" * 50)
>
> if __name__ == "__main__":
>     main()
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> /**
>  * Complete Trade Signal Generator
>  * Entry + SL + TP1 + TP2 + TP3
>  */
>
> const axios = require("axios");
>
> // === CONFIGURATION ===
> const API_KEY = "YOUR_API_KEY";
> const BASE_URL = "https://api.innova-trading.com";
> const SYMBOL = "EURUSD";
> const TIMEFRAME = 60;
>
> // Trading parameters
> const ATR_PERIOD = 14;
> const SL_ATR_MULTIPLIER = 1.5;
> const TP1_ATR_MULTIPLIER = 1.5;
> const TP2_ATR_MULTIPLIER = 3.0;
> const TP3_ATR_MULTIPLIER = 4.5;
>
> async function getBars(symbol, timeframe, limit = 500) {
>   const response = await axios.get(
>     `${BASE_URL}/api/external/bars/${symbol}/${timeframe}`,
>     {
>       params: { limit },
>       headers: { Authorization: `Bearer ${API_KEY}` },
>     }
>   );
>   return response.data.bars;
> }
>
> async function submitIndicator(indicatorId, points, symbol, timeframe, metadata = {}) {
>   const response = await axios.post(
>     `${BASE_URL}/api/external/indicators/${indicatorId}`,
>     {
>       symbol,
>       timeframe,
>       indicator_name: "Trade Signals (Entry + SL + TPs)",
>       version: "1.0",
>       points,
>       metadata,
>     },
>     {
>       headers: {
>         Authorization: `Bearer ${API_KEY}`,
>         "Content-Type": "application/json",
>       },
>     }
>   );
>   return response.data;
> }
>
> function calculateATR(bars, period = 14) {
>   const tr = [];
>
>   for (let i = 1; i < bars.length; i++) {
>     const high = bars[i].high;
>     const low = bars[i].low;
>     const prevClose = bars[i - 1].close;
>
>     const tr1 = high - low;
>     const tr2 = Math.abs(high - prevClose);
>     const tr3 = Math.abs(low - prevClose);
>
>     tr.push(Math.max(tr1, tr2, tr3));
>   }
>
>   const atr = new Array(bars.length).fill(null);
>
>   for (let i = period; i < bars.length; i++) {
>     let sum = 0;
>     for (let j = i - period; j < i; j++) {
>       sum += tr[j];
>     }
>     atr[i] = sum / period;
>   }
>
>   return atr;
> }
>
> function detectBullishSetup(bars, index) {
>   if (index < 3) return false;
>
>   for (let i = index - 2; i <= index; i++) {
>     if (bars[i].close <= bars[i].open) return false;
>   }
>
>   return true;
> }
>
> function detectBearishSetup(bars, index) {
>   if (index < 3) return false;
>
>   for (let i = index - 2; i <= index; i++) {
>     if (bars[i].close >= bars[i].open) return false;
>   }
>
>   return true;
> }
>
> function generateTradeSignals(bars) {
>   const atr = calculateATR(bars, ATR_PERIOD);
>   const points = [];
>
>   for (let i = Math.max(ATR_PERIOD, 3); i < bars.length; i++) {
>     const curr = bars[i];
>     const atrValue = atr[i];
>
>     if (atrValue === null) continue;
>
>     const barTime = curr.time;
>
>     // Bullish setup
>     if (detectBullishSetup(bars, i)) {
>       const entry = curr.close;
>       const sl = entry - atrValue * SL_ATR_MULTIPLIER;
>       const tp1 = entry + atrValue * TP1_ATR_MULTIPLIER;
>       const tp2 = entry + atrValue * TP2_ATR_MULTIPLIER;
>       const tp3 = entry + atrValue * TP3_ATR_MULTIPLIER;
>
>       points.push({
>         time: barTime,
>         type: "low",
>         price: entry,
>         label: "BUY",
>         color: "#3b82f6",
>         shape: "arrowUp",
>         size: 2,
>       });
>
>       points.push({
>         time: barTime,
>         type: "low",
>         price: sl,
>         label: "SL",
>         color: "#ef4444",
>         shape: "square",
>         size: 1,
>       });
>
>       [tp1, tp2, tp3].forEach((tpPrice, idx) => {
>         points.push({
>           time: barTime,
>           type: "high",
>           price: tpPrice,
>           label: `TP${idx + 1}`,
>           color: "#22c55e",
>           shape: "circle",
>           size: 1,
>         });
>       });
>     }
>
>     // Bearish setup
>     else if (detectBearishSetup(bars, i)) {
>       const entry = curr.close;
>       const sl = entry + atrValue * SL_ATR_MULTIPLIER;
>       const tp1 = entry - atrValue * TP1_ATR_MULTIPLIER;
>       const tp2 = entry - atrValue * TP2_ATR_MULTIPLIER;
>       const tp3 = entry - atrValue * TP3_ATR_MULTIPLIER;
>
>       points.push({
>         time: barTime,
>         type: "high",
>         price: entry,
>         label: "SELL",
>         color: "#f97316",
>         shape: "arrowDown",
>         size: 2,
>       });
>
>       points.push({
>         time: barTime,
>         type: "high",
>         price: sl,
>         label: "SL",
>         color: "#ef4444",
>         shape: "square",
>         size: 1,
>       });
>
>       [tp1, tp2, tp3].forEach((tpPrice, idx) => {
>         points.push({
>           time: barTime,
>           type: "low",
>           price: tpPrice,
>           label: `TP${idx + 1}`,
>           color: "#22c55e",
>           shape: "circle",
>           size: 1,
>         });
>       });
>     }
>   }
>
>   return points;
> }
>
> async function main() {
>   console.log("=".repeat(50));
>   console.log("Complete Trade Signal Generator");
>   console.log("=".repeat(50));
>
>   console.log(`\n1. Fetching ${SYMBOL} ${TIMEFRAME}m bars...`);
>   const bars = await getBars(SYMBOL, TIMEFRAME, 200);
>   console.log(`   Got ${bars.length} bars`);
>
>   console.log("\n2. Generating trade signals...");
>   const points = generateTradeSignals(bars);
>
>   const buys = points.filter((p) => p.label === "BUY").length;
>   const sells = points.filter((p) => p.label === "SELL").length;
>
>   console.log(`   BUY signals: ${buys}`);
>   console.log(`   SELL signals: ${sells}`);
>   console.log(`   Total points: ${points.length}`);
>
>   if (points.length > 0) {
>     console.log("\n3. Submitting to InnovaTrading...");
>     const result = await submitIndicator("trade_signals", points, SYMBOL, TIMEFRAME, {
>       atr_period: ATR_PERIOD,
>       sl_multiplier: SL_ATR_MULTIPLIER,
>       tp_multipliers: [TP1_ATR_MULTIPLIER, TP2_ATR_MULTIPLIER, TP3_ATR_MULTIPLIER],
>       buys,
>       sells,
>     });
>     console.log(`   Submitted ${result.points_received} points`);
>     console.log(`   Expires: ${result.expires_at}`);
>   } else {
>     console.log("\n   No trade setups found");
>   }
>
>   console.log("\n" + "=".repeat(50));
> }
>
> main().catch(console.error);
> ```

***

## Quick Reference

### Point Format

```python theme={null}
point = {
    "time": 1765540800,        # Unix timestamp (REQUIRED)
    "type": "high" | "low",    # Position on candle (REQUIRED)
    "price": 1.1725,           # Exact price (REQUIRED)
    "label": "BUY",            # Text to display
    "color": "#3b82f6",        # Hex color
    "shape": "arrowUp",        # circle, arrowUp, arrowDown, square
    "size": 2                  # 1 (small), 2 (medium), 3 (large)
}
```

### Recommended Colors

| Element | Color | Hex |
| - | - | - |
| Buy | Blue | `#3b82f6` |
| Sell | Orange | `#f97316` |
| Stop Loss | Red | `#ef4444` |
| Take Profit | Green | `#22c55e` |
| Neutral | Yellow | `#eab308` |
| Weak | Gray | `#94a3b8` |

### Available Shapes

| Shape | Common Use |
| - | - |
| `arrowUp` | Buy signals |
| `arrowDown` | Sell signals |
| `circle` | Levels, TPs |
| `square` | Stop Loss, S/R |

***

## Next Steps

> [card] [Continuous Integration](https://docs.innova-trading.com/guides/continuous-integration.md)
>
> Automate updates

> [card] [API Reference](https://docs.innova-trading.com/api-reference/introduction.md)
>
> Complete documentation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.