StockTracker — Complete System Guide

An NSE Nifty-100 swing & intraday screener with virtual paper trading, live KITE quotes, and 15 trading strategies running every 5 minutes during market hours.

1. Overview

StockTracker scans the Nifty 100 universe every 5 minutes during market hours (09:00–16:00 IST) against 15 hand-tuned trading strategies spanning bull/bear/sideways regimes, both swing and intraday. Qualifying signals are auto-entered into a virtual ₹80,000 paper portfolio. Live market prices come from Zerodha KITE (when configured) or Yahoo Finance as fallback. No real orders are ever placed.

Universe
Nifty 100

NSE equity, top 100 by market cap

Strategies
15 total

6 Bull-Swing · 2 Bull-Intraday · 4 Bear · 3 Sideways

Paper Capital
₹80,000

Virtual · 1 share per signal · Resettable

Read-only KITE access. The KITE client class is hard-restricted by a path whitelist and a __call blocker — no place_order code exists anywhere in the codebase. KITE is used only for live market quotes and historical OHLCV ingestion.

2. Architecture

Three independent layers communicating via MySQL + Redis:

                              ┌──────────────────────┐
                              │   Frontend (static)  │
                              │  login · dashboard   │
                              │  screener · paper    │
                              │  strategies · zero   │
                              └──────────┬───────────┘
                                         │ /api/*
                                         ▼
        ┌────────────────────────────────────────────────────────────┐
        │                  PHP API  (api/index.php)                  │
        │  ─────────────────────────────────────────────────────────  │
        │  AuthController  · BrokerConfigController                  │
        │  ScreenerController · StrategiesController                 │
        │  PaperTradingController · MarketController                 │
        │  WatchlistController · StockController                     │
        │                                                            │
        │  lib/KiteClient.php  (READ-ONLY, whitelist enforced)       │
        └─────────────┬────────────────────────────┬─────────────────┘
                      │                            │
                      ▼                            ▼
              ┌──────────────┐              ┌─────────────┐
              │    MySQL     │              │    Redis    │
              │              │              │   (cache)   │
              │ ohlcv_daily  │              └─────────────┘
              │ ohlcv_hourly │                     ▲
              │ stocks       │                     │
              │ users        │              ┌──────┴──────┐
              │ user_broker  │              │             │
              │ virtual_*    │       ┌──────┴──────┐ ┌────┴────────┐
              │ strategy_*   │       │   Python    │ │   Python    │
              │ screening_*  │       │  Ingestion  │ │  Strategies │
              │ ingestion_log│       │   Worker    │ │   Engine    │
              └──────────────┘       └──────┬──────┘ └─────┬───────┘
                                            │              │
                                            ▼              │
                                     ┌──────────────┐      │
                                     │   KITE API   │◄─────┘
                                     │              │ (live LTP +
                                     │   Yahoo API  │  historical)
                                     │  (fallback)  │
                                     └──────────────┘

Tech stack

LayerTechnologyFiles
FrontendVanilla JS + Tailwind CDN*.html · assets/js/*.js
APIPHP 8 (no framework)api/index.php · api/controllers/*
IngestionPython 3.10+ async (aiohttp)python/ingestion/
Strategy enginePython (pandas)python/screening/
Paper traderPythonpython/paper/
CacheRedis (optional)
StorageMySQL 8 (or MariaDB)database/*.sql
Data feedKITE Connect (live) · Yahoo (fallback)kite_historical_client.py · yahoo_client.py · kite_prices.py

3. Data Flow

Following a single trade from market to paper portfolio:

  ① 10:15 IST    ingest cron fires
                 ┌──────────────────────────────────────┐
                 │ python main.py ingest                │
                 │  → KiteHistoricalClient (preferred)  │
                 │  → YahooFinanceClient   (fallback)   │
                 └──────────────────────────────────────┘
                                  │
                                  ▼  upsert
                 ┌──────────────────────────────────────┐
                 │ ohlcv_daily   (1d candles, 2y back)  │
                 │ ohlcv_hourly  (1h candles, 60d back) │
                 └──────────────────────────────────────┘

  ② Every 5 min  strategies cron fires
     09:00-16:00 ┌──────────────────────────────────────┐
                 │ python main.py strategies            │
                 │  → load OHLCV from MySQL              │
                 │  → compute indicators (pandas)        │
                 │  → run 15 strategy fns concurrently   │
                 │  → produce StrategySignal[]          │
                 │  → persist signals                    │
                 └──────────────────────────────────────┘
                                  │
                                  ▼
                 ┌──────────────────────────────────────┐
                 │ strategy_signals (live table, 24h TTL)│
                 └──────────────────────────────────────┘
                                  │
                                  ▼  _paper_trade(signals)
                 ┌──────────────────────────────────────┐
                 │ PaperTrader.sweep_stale_intradays()  │ ← safety net
                 │ PaperTrader.auto_enter(signals)      │ ← BUY/SELL paper
                 │ PaperTrader.update_unrealized()      │
                 │ PaperTrader.check_swing_exits()      │
                 └──────────────────────────────────────┘
                                  │
                                  ▼
                 ┌──────────────────────────────────────┐
                 │ virtual_trades   (the paper ledger)  │
                 │ virtual_portfolio (cash + tallies)   │
                 └──────────────────────────────────────┘

  ③ 15:25 IST    paper-close cron fires
                 ┌──────────────────────────────────────┐
                 │ python main.py paper-close           │
                 │  → close all intraday positions      │
                 │  → exit price priority:              │
                 │      KITE LTP                        │
                 │       → today's hourly close         │
                 │       → today's daily close          │
                 │       → current_price                │
                 │       → entry_price (last resort)    │
                 └──────────────────────────────────────┘

  ④ User opens   /paper-trading.html
                 ┌──────────────────────────────────────┐
                 │ PaperTradingController (PHP)         │
                 │  → self-heal stuck-open rows         │
                 │  → sweepStaleIntradays()             │
                 │  → return trades + portfolio + perf  │
                 └──────────────────────────────────────┘
                                  │
                                  ▼
                 ┌──────────────────────────────────────┐
                 │ Browser renders:                     │
                 │   Open Positions · Closed Today      │
                 │   Today's Trades · Performance · etc │
                 │ LivePrices.fetch() overlays KITE LTP │
                 └──────────────────────────────────────┘

4. Cron Jobs

4.1 Cron table

Schedule (IST) Command Purpose
15 10 * * 1-5
Mon–Fri 10:15
$PY $APP ingest Morning OHLCV catch-up. Refreshes ohlcv_daily with yesterday's EOD bar (and intraday bars).
45 15 * * 1-5
Mon–Fri 15:45
$PY $APP ingest EOD OHLCV ingest, 15 min after market close. Today's 15:30 close lands in ohlcv_daily.
*/5 * * * 1-5
Every 5 min, gated 09–16 IST
$PY $APP screen Lightweight technical screener (RSI/EMA/Vol). Populates screening_results for the Screener page.
*/5 * * * 1-5
Every 5 min, gated 09–16 IST
$PY $APP strategies Runs the 15 strategy functions, persists signals, and triggers auto_enter for paper trades. This is the only job that opens new positions.
25 15 * * 1-5
Mon–Fri 15:25
$PY $APP paper-close Force-close all open intraday positions. Aligned with trade-window close so nothing newer than 15:25 IST can slip past.
* * * * *
Every minute
$PY scripts/watchdog.py Process health check. No trading logic; only alerts/recovery.

4.2 What each job does

ingest 10:15 + 15:45 IST · Mon–Fri

Pulls OHLCV bars from KITE first (if any user's access_token is fresh today) or falls back to Yahoo Finance. Upserts into ohlcv_daily and ohlcv_hourly.

Why two times? 10:15 catches up after yesterday's missed EOD; 15:45 lands today's close. The strategy scanner runs on this data — fresh OHLCV = accurate signals.

screen Every 5 min, 09–16 IST · Mon–Fri

Pure technical filter — computes RSI, EMAs, volume multiples, ATR%, MACD on every Nifty-100 stock, assigns a 0–100 signal_strength, and writes results to screening_results. Powers the /screener.html table. Does not open paper trades.

strategies Every 5 min, 09–16 IST · Mon–Fri

Heart of the system. Runs all 15 strategy functions on each stock; produces StrategySignal dataclasses with entry, SL, T1/T2/T3, R:R, confidence. Persists to strategy_signals. Then calls _paper_trade(signals) which:

  1. sweep_stale_intradays() — closes yesterday's intradays that the cron missed
  2. auto_enter(signals) — validates trigger + slippage cap + opens paper positions
  3. update_unrealized(prices) — refreshes P&L on open trades
  4. check_swing_exits() — closes swing trades that hit SL/target
paper-close 15:25 IST · Mon–Fri

Force-closes every open intraday position. Exit price uses the priority chain: live KITE LTP → today's hourly close → today's daily close → stored current_price → latest daily close → entry_price. Logs the actual source used per ticker for audit.

Timed at 15:25 IST to match the trade-window close (no new intraday can be entered after this point, so we capture everything within one sweep).

watchdog Every minute · all days

Health check — verifies the ingest/strategy crons fired on schedule, MySQL is reachable, Redis is alive. No trading logic. Logs anomalies to watchdog.log.

5. Strategies (15)

All strategies share a common dataclass output (StrategySignal): direction, entry, SL, T1/T2/T3, risk, R:R, signal_strength (0–100), confidence (HIGH/MEDIUM), and a human-readable reason string. Each function is a pure transform of pre-computed indicators (_ExtIndicators) and produces a signal only when every hard condition passes.

5.1 Bull Swing (6 strategies)

KeyNameHoldEdge
bb_squeezeBB Squeeze Breakout3–7dVolatility compression → expansion with volume confirmation
ema_pullbackEMA Pullback5–10dBuy the dip to EMA20/50 in confirmed uptrend (~60% win rate)
supertrend_flipSupertrend Flip4–8dIndicator flip triggers algo entries; momentum continuation
momentum_52w52-Week Breakout7–15dZero overhead resistance; pure price discovery
mean_reversionOversold Bounce3–6dRSI capitulation in macro uptrends; counter-trend (smaller size)
vol_accumulationVolume Accumulation7–15dSmart-money footprint before base breakout

5.2 Bull Intraday (2)

KeyNameR:R T3Edge
bull_orb_breakoutORB Long Breakout3.5:19:15–9:30 high broken on 2×+ volume; momentum + short-squeeze
bull_gap_momentumGap & Momentum3.8:1Gap-up above EMA20 that holds; MACD-confirmed continuation

5.3 Bear (4: 2 Intraday + 2 Swing)

KeyNameTypeEdge
bear_vwap_rejectionVWAP Rejection ShortIntradayFailed bounce at EMA20/VWAP in downtrend; tight R:R
bear_orb_breakdownORB Breakdown ShortIntradayFull bear stack + 3+ down days; institutional selling momentum
bear_ema_deathcrossEMA Death Cross ShortSwing 5–12dDeath-cross + RSI 40–62 sweet spot (max downside left)
bear_flag_breakdownBear Flag BreakdownSwing 5–10dWeak bounce on contracting volume; flagpole measured-move target

5.4 Sideways (3: 2 Intraday + 1 Swing)

KeyNameTypeEdge
sideways_nrd_breakoutNRD Coil BreakoutIntradayRange < 60% ATR; ATR-based targets = 4–6:1 R:R
sideways_inside_dayInside Day BreakoutIntradayInside-day in uptrend + ST/MACD; algo buy-stops trigger
sideways_bb_supportBB Range SupportSwing 3–7dEMA20≈EMA50 + price at BB lower + RSI oversold + volume spike
Strategy keys are the canonical identifiers — they appear in virtual_trades.strategy_key, strategy_signals.strategy_key, and the JS STRATEGY_NAMES/STRATEGY_COLORS maps. Changing a key requires a DB migration.

6. Trading Rules

Hard rules enforced by PaperTrader.auto_enter():

  1. Trade window: No new paper trades outside 09:20–15:25 IST, weekdays only. 5-min buffer at both ends of the 09:15–15:30 NSE session.
  2. Open-position block: If a ticker already has an OPEN paper position (any strategy), no new entry for that ticker — even from a different strategy.
  3. Cooldown: If (ticker, strategy_key) was traded and closed within the last 5 days, skip — wait for cooldown to expire. Different strategy on the same ticker is OK after cooldown.
  4. Confidence: Only HIGH or MEDIUM signals — never LOW.
  5. Cash check: Skip if current_balance < live_entry_price.
  6. Trigger validation: For LONG, execute only when live ≥ strategy_entry. For SHORT, execute only when live ≤ strategy_entry.
  7. Slippage cap: 0.5% for intraday strategies, 0.75% for swing strategies — skip "chasing" entries where live has already moved too far past the trigger.

Strategy vs Actual prices

Each paper trade stores both:

ColumnMeaning
strategy_entry_priceThe strategy's planned trigger level
entry_priceThe actual live execution price (used for P&L)
strategy_exit_priceThe strategy's planned exit level when an SL/target hit (NULL for MANUAL/INTRADAY_AUTO)
exit_priceThe actual live exit price (used for P&L)
target1/2/3, stop_lossStrategy's planned levels (unchanged)

Position sizing & portfolio

7. Pages & UI

All protected pages use a 4-item collapsible sidebar (Dashboard · Screener · Strategies · Paper Trading) plus a Broker settings button. The sidebar collapse-state persists in localStorage['sb_col']. auth.js blocks unauthenticated access via a global /api/auth/check probe.

7.1 login.html — Sign in

7.2 index.html — Dashboard

7.3 screener.html — Technical Screener

7.4 strategies.html — Strategy Explorer

7.5 paper-trading.html — Paper Trading Simulator

5 tabs across the top:

TabContent
OverviewPer-strategy cards: trades count, win rate, avg P&L, recent trades.
Open PositionsLive-overlaid current price (KITE LTP if connected), unrealized P&L. Expandable rows show planned vs actual entry, SL/targets with distance %, sector, signal strength, full entry time. Close button per row.
Closed Today4 summary tiles (count, P&L, wins, losses) + table of trades that exited today. Expandable rows show full entry/exit times, planned vs actual exit price, exit reason.
Today's TradesAll trades touching today (opened or closed). Same expandable detail panel.
PerformanceStrategy-level performance table — total/open/wins/losses, win-rate, avg %, total P&L.
HistoryPaginated list of all historical closed trades.

7.6 settings.html — Trading Parameters

Edit any of the 10 tunable trading parameters from the UI instead of source code. Changes apply on the next strategies-cron run (within 5 min). Grouped into four categories:

Settings are global (single row per key). Backed by the app_settings table. Python reads via settings_loader.py with hard-coded fallbacks.

7.7 zero.html — KITE Token Exchange

7.8 Broker Settings modal (sidebar → Broker)

8. Broker / Data Source

Two sources, with KITE strongly preferred when configured:

Yahoo Finance (default)

Zerodha KITE (preferred)

Daily KITE flow

  1. Sidebar → Broker → "Login with Zerodha →"
     │
     ▼
  2. Browser redirects to:
        https://kite.zerodha.com/connect/login?api_key=YOURKEY&v=3
     │
     ▼
  3. User signs in (Zerodha ID + password + TOTP)
     │
     ▼
  4. Zerodha redirects to:
        https://trade.recruval.in/zero.html?request_token=XXX&status=success
     │
     ▼
  5. zero.html JS captures request_token, POSTs to /api/broker/kite-token
     │
     ▼
  6. BrokerConfigController computes SHA256(api_key+request_token+api_secret)
     POSTs to https://api.kite.trade/session/token, gets access_token
     │
     ▼
  7. access_token saved to user_broker_config.kite_access_token
     kite_token_updated_at = NOW()
     │
     ▼
  8. /api/market/quote, /quote/ltp, /instruments/historical
     now all served from KITE for the rest of the day

Where each data source is used

ConsumerPrimaryFallback
Historical OHLCV ingest (Python)KITEYahoo
Live quotes for paper P&L (PHP/JS)KITELatest DB close
Intraday auto-close exit priceKITEhourly → daily → entry
Swing exit price (target/SL hit)KITEToday's daily close → target level
Manual close exit priceKITEhourly → daily

9. Paper Trading Engine

All paper-trade lifecycle methods live in python/paper/trader.py:

MethodWhen calledWhat it does
auto_enter(signals)Every strategies-cron runApplies all 7 rules; opens new paper positions at live execution price
update_unrealized(prices)Every strategies-cron runUpdates current_price and unrealized_pnl on every OPEN row
check_swing_exits()Every strategies-cron runFor each open swing trade, checks today's H/L vs SL/T1/T2/T3; closes if hit. Exit price = KITE LTP → today's close → level
auto_exit_intraday()15:25 IST cron (paper-close)Closes ALL open intraday positions. Exit price via 6-level priority chain (KITE LTP best, entry_price worst)
sweep_stale_intradays()Every strategies-cron + every PHP API callSafety net — closes any intraday whose entry_time < CURDATE() (cron missed yesterday)

Exit reasons (enum)

10. Database Schema

TablePurposeNotable columns
stocksNifty 100 universe (static)ticker, company_name, sector, exchange
ohlcv_daily2 years of daily candlesticker, date, open, high, low, close, volume
ohlcv_hourly60 days of hourly candlesticker, datetime, OHLCV
usersAuth (bcrypt-hashed passwords)username, password_hash, is_active, locked_until, last_login
user_broker_configPer-user data source + KITE credsdata_source, kite_api_key, kite_api_secret, kite_access_token, kite_token_updated_at
screening_resultsLatest technical-screener outputticker, signal_strength, RSI, ATR%, vol_mult, …
strategy_signalsLive signal table (24h retention)strategy_key, direction, entry, SL, targets, R:R, signal_strength, confidence, reason
virtual_portfolioSingle-row cash + talliescurrent_balance, total_invested, total_pnl, trades_total/won/lost
virtual_tradesThe paper-trade ledgerdirection, is_intraday, entry_price, strategy_entry_price, exit_price, strategy_exit_price, exit_reason, pnl, status
watchlistsPer-user watchlistuser_id, ticker
ingestion_logPer-run audit of OHLCV pullsticker, source ('kite'/'yahoo'), status, records_upserted
app_settingsTunable trading parameters (Settings page)setting_key, setting_value, value_type, label, description, category, min_value, max_value

Migrations

Run in order on a fresh install:

mysql -u app -p stocktracker < database/schema.sql
mysql -u app -p stocktracker < database/nifty100_stocks.sql
mysql -u app -p stocktracker < database/add_users.sql
mysql -u app -p stocktracker < database/add_direction_column.sql
mysql -u app -p stocktracker < database/add_strategy_signals.sql
mysql -u app -p stocktracker < database/add_paper_trading.sql
mysql -u app -p stocktracker < database/add_broker_config.sql
mysql -u app -p stocktracker < database/add_strategy_prices.sql
mysql -u app -p stocktracker < database/add_app_settings.sql

# Optional / on-demand
mysql -u app -p stocktracker < database/repair_paper_trades.sql

11. API Endpoints

All routes registered in api/index.php. Public routes (/api/auth/*) skip the auth guard; everything else requires $_SESSION['user_id'].

MethodPathPurpose
POST/api/auth/loginUsername + password (optionally + data_source + KITE creds)
POST/api/auth/logoutClear session
GET/api/auth/checkSession probe — returns user + broker config view
GET/api/screener/resultsLatest technical screener output
GET/api/screener/statsAggregate counts (strong / moderate / total / avg)
GET/api/stocks/universeFull Nifty 100 list
GET/api/stocks/{ticker}/chart-dataOHLCV for chart modal
GET/api/stocks/{ticker}/indicatorsPre-computed indicators
GET/api/strategies/listStrategy metadata for cards
GET/api/strategies/resultsCurrent strategy signals (filterable)
GET/api/strategies/summaryPer-strategy aggregate counts
GET/api/paper/dashboardPortfolio + open count + today's totals
GET/api/paper/tradesFilterable trades list (status, strategy, date)
GET/api/paper/performancePer-strategy win rates & P&L
POST/api/paper/close/{id}Manual close at live KITE price
POST/api/paper/resetWipe trades + reset cash (requires confirm)
GET / POST/api/broker/configGet / update data_source + KITE creds (public view masks secrets)
POST/api/broker/testVerify KITE creds via /user/profile
POST/api/broker/kite-login-urlBuild the Zerodha sign-in URL
POST/api/broker/kite-tokenExchange request_token for access_token
GET/api/market/quoteLive quotes (KITE if user is on KITE, else Yahoo EOD)
GET/api/settingsGet all tunable trading parameters with metadata
POST/api/settingsBulk update — server validates type, range, enum, cross-field
GET / POST / DELETE/api/watchlistPer-user watchlist CRUD

12. Safety Guarantees

No real orders — three independent layers

  1. Code structurally cannot place orders. KiteClient only has a get() method — no post(), put(), or delete(). The ALLOWED_PATHS whitelist rejects any path outside read-only market-data endpoints. __call blocks any undefined method invocation with a clear error.
  2. Codebase audit. Zero matches for place_order, /orders, place_trade across the entire repo. The only POST to KITE is /session/token (auth, not orders) and is commented as such.
  3. UI is honest. The Paper Trading toolbar always shows a green "PAPER ONLY · No real orders" badge. The Broker modal repeats this in a green callout when KITE is selected.

Data self-healing

Credential handling

13. Troubleshooting

"Intraday trades from yesterday still showing as OPEN"

Likely the paper-close cron didn't fire (server down, cron mis-scheduled). Self-heal will fix on next page load. To confirm:

tail -50 $LOG/paper.log
crontab -l | grep paper-close
# Should show:  25 15 * * 1-5  $PY $APP paper-close ...

"PAPER trigger skip" appearing in logs

Working as designed. Means a signal fired but the live price had already moved > 0.5% / 0.75% past the trigger — system avoided "chasing" the move. Tune the slippage cap in trader.py (MAX_SLIPPAGE_INTRADAY / MAX_SLIPPAGE_SWING) if too strict.

"KITE token expired or invalid"

KITE access_tokens expire at 06:00 IST daily. Sidebar → Broker → "Login with Zerodha →" to mint a fresh one. The /api/market/quote endpoint silently falls back to Yahoo EOD when this happens — UI shows an amber warning banner.

Wrong times displayed in trade details

MySQL TIMESTAMPs are stored in the server's session timezone (IST). The JS parser treats them as local without appending " UTC". If you see times off by +5:30 hours, server timezone configuration likely changed — check SELECT @@session.time_zone, @@global.time_zone, NOW().

Re-running migrations safely

All migrations are idempotent — they use either CREATE TABLE IF NOT EXISTS or a stored-procedure check against information_schema. Safe to re-run after a code update.

Reset the paper portfolio

curl -X POST http://localhost/api/paper/reset \
  -H "Content-Type: application/json" \
  -b "PHPSESSID=<your-session>" \
  -d '{"confirm":"RESET_CONFIRMED"}'

Or simply click Reset in the Paper Trading toolbar.

14. File Map

stockTracker/
├── api/
│   ├── index.php                              # Router + auth guard
│   ├── config/
│   │   ├── bootstrap.php                      # Session start
│   │   └── database.php                       # PDO + Redis singletons
│   ├── core/
│   │   └── Router.php                         # GET/POST/DELETE + path params
│   ├── lib/
│   │   ├── KiteClient.php                     # READ-ONLY KITE REST client
│   │   └── BrokerConfig.php                   # Per-user broker config helper
│   └── controllers/
│       ├── AuthController.php                 # Login / logout / check
│       ├── ScreenerController.php             # Technical screener data
│       ├── StockController.php                # Universe / chart-data / indicators
│       ├── StrategiesController.php           # 15-strategy metadata + signals
│       ├── PaperTradingController.php         # Paper trade lifecycle
│       ├── BrokerConfigController.php         # KITE creds + token exchange
│       ├── MarketController.php               # Live quote pass-through
│       ├── WatchlistController.php
│       └── DiagController.php
├── python/
│   ├── main.py                                # CLI dispatch (ingest/screen/strategies/paper-close)
│   ├── config.py                              # Dataclass-based settings
│   ├── models/
│   │   ├── database.py                        # get_cursor() context manager
│   │   └── cache.py                           # Redis wrapper
│   ├── ingestion/
│   │   ├── worker.py                          # Async batch ingester (KITE-first)
│   │   ├── yahoo_client.py                    # Yahoo OHLCV (fallback)
│   │   └── kite_historical_client.py          # KITE historical OHLCV
│   ├── screening/
│   │   ├── indicators.py                      # EMA / RSI / BB / ATR / MACD / Supertrend
│   │   ├── strategies.py                      # 15 strategy functions
│   │   └── strategy_engine.py                 # Concurrent runner + _paper_trade
│   └── paper/
│       ├── trader.py                          # auto_enter / exits / sweep / cooldown
│       └── kite_prices.py                     # Sync KITE LTP for paper-close cron
├── database/
│   ├── schema.sql                             # Core tables
│   ├── nifty100_stocks.sql                    # Universe seed
│   ├── add_users.sql                          # Auth table
│   ├── add_direction_column.sql               # LONG/SHORT migration
│   ├── add_strategy_signals.sql               # Live signals table
│   ├── add_paper_trading.sql                  # virtual_portfolio + virtual_trades
│   ├── add_broker_config.sql                  # user_broker_config
│   ├── add_strategy_prices.sql                # strategy_entry/exit_price columns
│   └── repair_paper_trades.sql                # One-shot data cleanup
├── cron/
│   └── stocktracker.cron                      # ingest / screen / strategies / paper-close / watchdog
├── assets/
│   ├── css/app.css                            # Sidebar + nav-link styles
│   └── js/
│       ├── auth.js                            # Session guard + global fetch interceptor
│       ├── sidebar.js                         # Sidebar collapse persistence
│       ├── api.js                             # API fetch wrapper
│       ├── broker.js                          # Broker settings modal
│       ├── livePrices.js                      # /api/market/quote helper + DOM overlay
│       ├── chart.js                           # Lightweight-charts modal
│       ├── home.js                            # Dashboard page
│       ├── dashboard.js                       # Screener page (legacy naming)
│       ├── strategies.js                      # Strategy explorer page
│       └── paper.js                           # Paper trading page (5 tabs)
├── login.html
├── index.html         (Dashboard)
├── screener.html      (Technical Screener)
├── strategies.html    (Strategy Explorer)
├── paper-trading.html (Paper Trading Simulator)
├── zero.html          (KITE token landing)
└── guide.html         (this document)

StockTracker · NSE Nifty-100 Swing & Intraday Screener with Paper Trading

Paper trading only — no real orders are ever placed.

↑ Back to top