2026-01-31 02:59:49 +08:00
# QuantDinger Changelog
This document records version updates, new features, bug fixes, and database migration instructions.
---
2026-03-01 03:42:10 +08:00
## V2.2.2 (2026-02-28)
### 🚀 New Features
#### Polymarket Prediction Markets Integration 🔮
- **Prediction Market Analysis**: Integrated Polymarket prediction markets as a new data source for AI analysis
- **AI-Driven Insights**: AI analyzes prediction market events and compares AI predictions with market consensus
- **Opportunity Discovery**: Identifies undervalued prediction opportunities with AI vs market divergence analysis
- **Asset Trading Recommendations**: Links prediction market events to related asset trading opportunities (e.g., BTC/USDT, ETH/USDT)
- **Data Analysis Only**: Focuses on data analysis and trading opportunity recommendations without live trading
- **Frontend Pages**: New `/polymarket` page with market listings, filtering, sorting, and search functionality
- **Market Detail View**: Comprehensive analysis view showing market info, AI analysis results, and related asset opportunities
- **AI Trading Radar Integration**: Prediction market opportunities appear in the AI Trading Radar alongside Crypto, US Stocks, and Forex
### 🐛 Bug Fixes
- Fixed duplicate `common.refresh` key in internationalization files (`zh-CN.js` and `en-US.js` )
- Fixed OKX position `entry_price` extraction (now correctly reads `avgPx` , `avgPxEp` , or `last` from position data)
- Improved symbol normalization across all exchanges to handle edge cases (e.g., PI, TRX without quote currency)
- Enhanced LLM provider fallback mechanism to handle 403/402/404/429 errors automatically
### 🎨 UI/UX Improvements
- Added Polymarket market cards with AI analysis summaries and opportunity scores
- Enhanced AI Trading Radar to display prediction market opportunities with distinct styling
- Improved symbol selector in Quick Trade panel with watchlist integration
### 📋 Database Migration
**Run the following SQL on your PostgreSQL database before deploying V2.2.2:**
```sql
-- ============================================================
-- QuantDinger V2.2.2 Database Migration
-- Polymarket Prediction Markets Integration
-- ============================================================
-- 预测市场表(缓存)
CREATE TABLE IF NOT EXISTS qd_polymarket_markets (
id SERIAL PRIMARY KEY ,
market_id VARCHAR ( 255 ) UNIQUE NOT NULL ,
question TEXT ,
category VARCHAR ( 100 ), -- crypto, politics, economics, sports
current_probability DECIMAL ( 5 , 2 ), -- YES概率(0-100)
volume_24h DECIMAL ( 20 , 2 ),
liquidity DECIMAL ( 20 , 2 ),
end_date_iso TIMESTAMP ,
status VARCHAR ( 50 ), -- active, closed, resolved
outcome_tokens JSONB , -- YES/NO价格和交易量
slug VARCHAR ( 255 ), -- Polymarket事件slug,用于构建URL
created_at TIMESTAMP DEFAULT NOW (),
updated_at TIMESTAMP DEFAULT NOW ()
);
-- 添加slug字段(如果表已存在但字段不存在)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_polymarket_markets' AND column_name = 'slug'
) THEN
ALTER TABLE qd_polymarket_markets ADD COLUMN slug VARCHAR ( 255 );
RAISE NOTICE 'Added slug column to qd_polymarket_markets' ;
END IF ;
END $$ ;
CREATE INDEX IF NOT EXISTS idx_polymarket_category ON qd_polymarket_markets ( category );
CREATE INDEX IF NOT EXISTS idx_polymarket_status ON qd_polymarket_markets ( status );
CREATE INDEX IF NOT EXISTS idx_polymarket_updated ON qd_polymarket_markets ( updated_at DESC );
-- AI分析记录表
CREATE TABLE IF NOT EXISTS qd_polymarket_ai_analysis (
id SERIAL PRIMARY KEY ,
market_id VARCHAR ( 255 ) NOT NULL ,
user_id INTEGER , -- 可选:用户特定的分析
ai_predicted_probability DECIMAL ( 5 , 2 ),
market_probability DECIMAL ( 5 , 2 ),
divergence DECIMAL ( 5 , 2 ), -- AI - 市场
recommendation VARCHAR ( 20 ), -- YES/NO/HOLD
confidence_score DECIMAL ( 5 , 2 ),
opportunity_score DECIMAL ( 5 , 2 ),
reasoning TEXT ,
key_factors JSONB ,
related_assets TEXT [], -- 相关资产列表
created_at TIMESTAMP DEFAULT NOW ()
);
CREATE INDEX IF NOT EXISTS idx_polymarket_analysis_market ON qd_polymarket_ai_analysis ( market_id );
CREATE INDEX IF NOT EXISTS idx_polymarket_analysis_opportunity ON qd_polymarket_ai_analysis ( opportunity_score DESC );
CREATE INDEX IF NOT EXISTS idx_polymarket_analysis_user ON qd_polymarket_ai_analysis ( user_id );
-- 资产交易机会表(基于预测市场生成)
CREATE TABLE IF NOT EXISTS qd_polymarket_asset_opportunities (
id SERIAL PRIMARY KEY ,
market_id VARCHAR ( 255 ) NOT NULL ,
asset_symbol VARCHAR ( 100 ),
asset_market VARCHAR ( 50 ),
signal VARCHAR ( 20 ), -- BUY/SELL/HOLD
confidence DECIMAL ( 5 , 2 ),
reasoning TEXT ,
entry_suggestion JSONB , -- 入场建议
created_at TIMESTAMP DEFAULT NOW ()
);
CREATE INDEX IF NOT EXISTS idx_polymarket_opp_market ON qd_polymarket_asset_opportunities ( market_id );
CREATE INDEX IF NOT EXISTS idx_polymarket_opp_asset ON qd_polymarket_asset_opportunities ( asset_symbol , asset_market );
-- Migration Complete
DO $$
BEGIN
RAISE NOTICE '✅ QuantDinger V2.2.2 database migration completed!' ;
END $$ ;
```
**Migration Notes:**
- All statements use `IF NOT EXISTS` — safe to run multiple times
- No existing data is modified or deleted
- New tables are created for Polymarket data caching and AI analysis
- Polymarket integration is read-only (data analysis only, no live trading)
### 📝 Configuration Notes
- No new environment variables required for basic Polymarket integration
- Polymarket data source uses placeholder/dummy data by default (can be extended with actual API integration)
- AI analysis leverages existing LLM configuration from System Settings
---
2026-02-27 01:57:04 +08:00
## V2.2.1 (2026-02-27)
### 🚀 New Features
#### Membership & Billing System
- **Subscription Plans**: Monthly / Yearly / Lifetime tiers with configurable pricing and credit bundles
- **Credit System**: Each plan includes credits; lifetime members receive recurring monthly credit bonuses
- **Plan Management**: All plan prices, credits, and bonus amounts configurable via System Settings → Billing Configuration
- **Membership Orders**: Order tracking with status management (paid / pending / failed / refunded)
#### USDT On-Chain Payment (TRC20)
- **HD Wallet Integration**: Per-order unique receiving address derived from xpub (BIP-32/44) — no private key on server
- **Automatic Reconciliation**: Background polling via TronGrid API detects incoming payments and confirms orders
- **Depth-Flexible xpub**: Supports both account-level (depth=3) and change-level (depth=4) xpub keys
- **Configurable Expiry**: Order expiration time and confirmation delay configurable in System Settings
- **Scan-to-Pay Modal**: Professional checkout UI with QR code, step indicator, real-time status, copy-to-clipboard, dark theme support
#### VIP Free Indicators
- **VIP Free Tag**: Admins can mark community indicators as "VIP Free" when publishing
- **Zero-Credit Access**: VIP members can use VIP-free indicators without spending credits
- **Visual Badge**: VIP Free indicators display a distinct badge in the Indicator Market
#### AI Trading Opportunities Radar
- **Multi-Market Scanning**: Auto-scans Crypto, US Stocks, and Forex markets every hour
- **Rolling Carousel**: Opportunities displayed in a rotating carousel with market-specific styling
- **Signal Classification**: BUY / SELL signals with percentage change and reason text
- **Multi-Language**: All radar card content fully internationalized
#### Simplified Strategy Creation
- **Simple / Advanced Mode Toggle**: New users start with simplified mode, power users can switch to advanced
- **Smart Defaults**: 15-minute K-line period, 5x leverage, market order, sensible TP/SL percentages
- **Live Trading Disclaimer**: Mandatory risk acknowledgment checkbox before enabling live trading
#### System Settings Simplification
- **Streamlined Configuration**: Removed redundant config groups (server, strategy); consolidated into essential categories
- **Market Order Default**: Changed default order mode to market order for reliable execution
- **Billing Config i18n**: All billing configuration items fully multi-language supported
2026-02-27 19:57:23 +08:00
#### Quick Trade Panel (闪电交易) 🆕
- **Side-Sliding Drawer**: Professional trading panel slides in from the right, allowing instant order placement without leaving the analysis page
- **Multi-Exchange Support**: Select from saved exchange credentials (Binance, OKX, Bitget, Bybit, etc.) with real-time balance display
- **Long/Short Toggle**: Color-coded direction buttons with one-click switching
- **Market / Limit Orders**: Toggle between market and limit order types; limit orders accept a specific price
- **Leverage Slider**: Interactive 1x– 125x leverage control for futures trading
- **TP/SL Price Setting**: Optional take-profit and stop-loss by **absolute price** (not percentage)
- **Current Position Display**: Shows open position with side, size, entry price, unrealized PnL, and one-click close button
- **Recent Trade History**: Displays last 5 quick trades with status tags
- **AI Radar Integration**: "Trade Now" button on each AI Trading Opportunities card pre-fills symbol, direction, and price
- **Indicator Analysis Integration**: Quick Trade button in chart header and floating ⚡ button pre-fills current symbol and price
- **Auto-Polling**: Balance and position data refresh every 10 seconds
- **Full Dark Theme**: Complete dark mode support for all panel elements
- **Multi-Language**: All labels and messages fully internationalized (zh-CN / en-US)
2026-02-27 01:57:04 +08:00
#### Indicator Market Performance Tracking
- **Live Performance Data**: Fixed aggregation to correctly parse backtest `result_json` and include live trade data
- **Combined Metrics**: Backtest return, live PnL, and win rate now properly displayed on indicator cards
### 🐛 Bug Fixes
2026-02-27 19:57:23 +08:00
- Fixed `quick_trade.py` importing from non-existent `auth_utils` module (corrected to `auth` )
2026-02-27 01:57:04 +08:00
- Fixed "Live Performance" data showing all zeros in Indicator Market (incorrect SQL query referencing non-existent columns)
- Fixed incorrect entry price display in Position Records (was falling back to current price)
- Fixed inaccurate System Overview statistics for running strategies, total capital, and total PnL
- Fixed multiple duplicate i18n key issues in `zh-CN.js` and `en-US.js` causing ESLint build failures
- Fixed exposed i18n keys (`common.loading` , `common.noData` , `systemOverview.*` ) not configured
- Fixed HTML nesting issues in trading assistant strategy creation form
- Fixed `ed25519-blake2b` build failure in Docker by adding temporary build dependencies
- Fixed "Current depth (3) is not suitable for deriving address" error for xpub — now compatible with both depth 3 and depth 4
### 🎨 UI/UX Improvements
- Removed "Total Analyses" / "Accuracy Rate" row from homepage AI Analysis section
- Removed "Search" and "Portfolio Checkup" features from AI Asset Analysis page
- Professional USDT checkout modal with custom header, step indicator, dual-column layout
- Dark theme and mobile responsive support for payment modal
- Trading Opportunities Radar carousel with smooth scrolling animation
### 📋 Database Migration
**Run the following SQL on your PostgreSQL database before deploying V2.2.1:**
```sql
-- ============================================================
-- QuantDinger V2.2.1 Database Migration
-- Membership, USDT Payment, VIP Free Indicators
-- ============================================================
-- 1. User Table: Add membership columns
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_users' AND column_name = 'vip_plan'
) THEN
ALTER TABLE qd_users ADD COLUMN vip_plan VARCHAR ( 20 ) DEFAULT '' ;
RAISE NOTICE 'Added vip_plan column to qd_users' ;
END IF ;
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_users' AND column_name = 'vip_is_lifetime'
) THEN
ALTER TABLE qd_users ADD COLUMN vip_is_lifetime BOOLEAN DEFAULT FALSE ;
RAISE NOTICE 'Added vip_is_lifetime column to qd_users' ;
END IF ;
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_users' AND column_name = 'vip_monthly_credits_last_grant'
) THEN
ALTER TABLE qd_users ADD COLUMN vip_monthly_credits_last_grant TIMESTAMP ;
RAISE NOTICE 'Added vip_monthly_credits_last_grant column to qd_users' ;
END IF ;
END $$ ;
-- 2. Indicator Codes: Add VIP Free flag
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'vip_free'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN vip_free BOOLEAN DEFAULT FALSE ;
RAISE NOTICE 'Added vip_free column to qd_indicator_codes' ;
END IF ;
END $$ ;
-- 3. Membership Orders table
CREATE TABLE IF NOT EXISTS qd_membership_orders (
id SERIAL PRIMARY KEY ,
user_id INTEGER NOT NULL REFERENCES qd_users ( id ) ON DELETE CASCADE ,
plan VARCHAR ( 20 ) NOT NULL ,
price_usd DECIMAL ( 10 , 2 ) DEFAULT 0 ,
status VARCHAR ( 20 ) DEFAULT 'paid' ,
created_at TIMESTAMP DEFAULT NOW (),
paid_at TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_membership_orders_user_id ON qd_membership_orders ( user_id );
-- 4. USDT Orders table (on-chain payment tracking)
CREATE TABLE IF NOT EXISTS qd_usdt_orders (
id SERIAL PRIMARY KEY ,
user_id INTEGER NOT NULL REFERENCES qd_users ( id ) ON DELETE CASCADE ,
plan VARCHAR ( 20 ) NOT NULL ,
chain VARCHAR ( 20 ) NOT NULL DEFAULT 'TRC20' ,
amount_usdt DECIMAL ( 20 , 6 ) NOT NULL DEFAULT 0 ,
address_index INTEGER NOT NULL DEFAULT 0 ,
address VARCHAR ( 80 ) NOT NULL DEFAULT '' ,
status VARCHAR ( 20 ) NOT NULL DEFAULT 'pending' ,
tx_hash VARCHAR ( 120 ) DEFAULT '' ,
paid_at TIMESTAMP ,
confirmed_at TIMESTAMP ,
expires_at TIMESTAMP ,
created_at TIMESTAMP DEFAULT NOW (),
updated_at TIMESTAMP DEFAULT NOW ()
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_usdt_orders_address_unique ON qd_usdt_orders ( chain , address );
CREATE INDEX IF NOT EXISTS idx_usdt_orders_user_id ON qd_usdt_orders ( user_id );
CREATE INDEX IF NOT EXISTS idx_usdt_orders_status ON qd_usdt_orders ( status );
2026-02-27 19:57:23 +08:00
-- 5. Quick Trades table (manual / discretionary orders from Quick Trade Panel)
CREATE TABLE IF NOT EXISTS qd_quick_trades (
id SERIAL PRIMARY KEY ,
user_id INTEGER NOT NULL REFERENCES qd_users ( id ) ON DELETE CASCADE ,
credential_id INTEGER DEFAULT 0 ,
exchange_id VARCHAR ( 40 ) NOT NULL DEFAULT '' ,
symbol VARCHAR ( 60 ) NOT NULL DEFAULT '' ,
side VARCHAR ( 10 ) NOT NULL DEFAULT '' , -- buy / sell
order_type VARCHAR ( 20 ) NOT NULL DEFAULT 'market' , -- market / limit
amount DECIMAL ( 24 , 8 ) DEFAULT 0 ,
price DECIMAL ( 24 , 8 ) DEFAULT 0 ,
leverage INTEGER DEFAULT 1 ,
market_type VARCHAR ( 20 ) DEFAULT 'swap' , -- swap / spot
tp_price DECIMAL ( 24 , 8 ) DEFAULT 0 ,
sl_price DECIMAL ( 24 , 8 ) DEFAULT 0 ,
status VARCHAR ( 20 ) DEFAULT 'submitted' , -- submitted / filled / failed / cancelled
exchange_order_id VARCHAR ( 120 ) DEFAULT '' ,
filled_amount DECIMAL ( 24 , 8 ) DEFAULT 0 ,
avg_fill_price DECIMAL ( 24 , 8 ) DEFAULT 0 ,
error_msg TEXT DEFAULT '' ,
source VARCHAR ( 40 ) DEFAULT 'manual' , -- ai_radar / ai_analysis / indicator / manual
raw_result JSONB ,
created_at TIMESTAMP DEFAULT NOW ()
);
CREATE INDEX IF NOT EXISTS idx_quick_trades_user ON qd_quick_trades ( user_id );
CREATE INDEX IF NOT EXISTS idx_quick_trades_created ON qd_quick_trades ( created_at DESC );
2026-02-27 01:57:04 +08:00
-- Migration Complete
DO $$
BEGIN
RAISE NOTICE '✅ QuantDinger V2.2.1 database migration completed!' ;
END $$ ;
```
**Migration Notes:**
- All statements use `IF NOT EXISTS` — safe to run multiple times
- No existing data is modified or deleted
- New `.env` variables required for USDT payment: `USDT_PAY_ENABLED` , `USDT_TRC20_XPUB` , `TRONGRID_API_KEY`
- New `.env` variables for membership pricing: `MEMBERSHIP_MONTHLY_PRICE_USD` , `MEMBERSHIP_MONTHLY_CREDITS` , etc.
- See `backend_api_python/env.example` for all new configuration options
### 📝 Configuration Notes
New environment variables (all optional, with defaults):
| Variable | Default | Description |
|----------|---------|-------------|
| `MEMBERSHIP_MONTHLY_PRICE_USD` | `19.9` | Monthly plan price |
| `MEMBERSHIP_MONTHLY_CREDITS` | `500` | Credits included in monthly plan |
| `MEMBERSHIP_YEARLY_PRICE_USD` | `169` | Yearly plan price |
| `MEMBERSHIP_YEARLY_CREDITS` | `8000` | Credits included in yearly plan |
| `MEMBERSHIP_LIFETIME_PRICE_USD` | `499` | Lifetime plan price |
| `MEMBERSHIP_LIFETIME_CREDITS` | `30000` | Initial credits for lifetime plan |
| `MEMBERSHIP_LIFETIME_MONTHLY_BONUS` | `500` | Monthly bonus credits for lifetime members |
| `USDT_PAY_ENABLED` | `false` | Enable USDT TRC20 payment |
| `USDT_TRC20_XPUB` | _(empty)_ | TRC20 HD wallet xpub for address derivation |
| `TRONGRID_API_KEY` | _(empty)_ | TronGrid API key for on-chain monitoring |
| `USDT_ORDER_EXPIRE_MINUTES` | `30` | USDT order expiration time |
---
2026-02-10 15:18:45 +08:00
## V2.1.3 (2026-02-XX)
### 🚀 New Features
#### Cross-Sectional Strategy Support
- **Multi-Symbol Portfolio Management** - Added support for cross-sectional strategies that manage a portfolio of multiple symbols simultaneously
- Strategy type selection: Single Symbol vs Cross-Sectional
- Symbol list configuration: Select multiple symbols for portfolio management
- Portfolio size: Configure the number of symbols to hold simultaneously
- Long/Short ratio: Set the proportion of long vs short positions (0-1)
- Rebalance frequency: Daily, Weekly, or Monthly portfolio rebalancing
- Indicator execution: Indicators receive a `data` dictionary (symbol -> DataFrame) for cross-symbol analysis
- Signal generation: Automatic buy/sell/close signals based on indicator rankings
- Parallel execution: Multiple orders executed concurrently for efficiency
- **Backend Implementation**
- Cross-sectional configurations stored in `trading_config` JSON field
- New `_run_cross_sectional_strategy_loop` method in TradingExecutor
- Automatic rebalancing based on configured frequency
- Support for both long and short positions in the same portfolio
- **Frontend UI**
- Strategy type selector in strategy creation/editing form
- Conditional display of single-symbol vs cross-sectional configuration fields
- Multi-select symbol picker for cross-sectional strategies
- Full i18n support (Chinese and English)
See `docs/CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md` or `docs/CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md` for detailed usage instructions.
### 🐛 Bug Fixes
- Fixed decimal precision issues in exchange order quantities (Binance Spot LOT_SIZE filter errors)
- Improved `_dec_str` method across all exchange clients for accurate quantity formatting
- Enhanced quantity normalization to respect exchange precision requirements
- Fixed validation logic for cross-sectional strategies (now validates correct symbol list field)
- Fixed success message to show correct strategy count for cross-sectional strategies
### 📋 Database Migration
**Run the following SQL on your PostgreSQL database before deploying V2.1.3:**
```sql
-- ============================================================
-- QuantDinger V2.1.3 Database Migration
-- Cross-Sectional Strategy Support
-- ============================================================
-- Add last_rebalance_at column to track rebalancing time for cross-sectional strategies
-- Note: Cross-sectional strategy configurations (symbol_list, portfolio_size, long_ratio, rebalance_frequency)
-- are stored in the trading_config JSON field, not as separate database columns.
-- This migration only adds the last_rebalance_at timestamp field which is needed for rebalancing logic.
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_strategies_trading'
AND column_name = 'last_rebalance_at'
) THEN
ALTER TABLE qd_strategies_trading
ADD COLUMN last_rebalance_at TIMESTAMP ;
RAISE NOTICE 'Added last_rebalance_at column to qd_strategies_trading' ;
ELSE
RAISE NOTICE 'Column last_rebalance_at already exists' ;
END IF ;
END $$ ;
```
**Migration Notes:**
- This migration is safe to run multiple times (uses IF NOT EXISTS check)
- Cross-sectional strategy configurations are stored in the `trading_config` JSON field, so no additional columns are needed
- The `last_rebalance_at` field is used to track when the last rebalancing occurred for cross-sectional strategies
- If you don't run this migration, cross-sectional strategies will still work, but rebalancing frequency checks may not function correctly
---
2026-02-01 15:02:14 +08:00
## V2.1.2 (2026-02-01)
### 🚀 New Features
#### Indicator Parameter Support
- **External Parameter Passing** - Indicators can now declare parameters using `# @param` syntax that can be configured per-strategy
- Supported types: `int` , `float` , `bool` , `str`
- Parameters are displayed in the strategy creation form after selecting an indicator
- Different strategies using the same indicator can have different parameter values
- **Cross-Indicator Calling** - Indicators can now call other indicators using `call_indicator(id_or_name, df)` function
- Supports calling by indicator ID (number) or name (string)
- Maximum call depth of 5 to prevent circular dependencies
- Only allows calling own indicators or published community indicators
#### Parameter Declaration Syntax
```
# @param <name> <type> <default> <description>
```
| Field | Description | Example |
|-------|-------------|---------|
| name | Parameter name (variable name) | `ma_fast` |
| type | Data type: `int` , `float` , `bool` , `str` | `int` |
| default | Default value | `5` |
| description | Description (shown in UI tooltip) | `Short-term MA period` |
#### Example: Dual Moving Average with Parameters
```python
# @param sma_short int 14 Short-term MA period
# @param sma_long int 28 Long-term MA period
# Get parameters
sma_short_period = params . get ( 'sma_short' , 14 )
sma_long_period = params . get ( 'sma_long' , 28 )
my_indicator_name = "Dual MA Strategy"
my_indicator_description = f "SMA { sma_short_period } / { sma_long_period } crossover"
df = df . copy ()
sma_short = df [ "close" ] . rolling ( sma_short_period ) . mean ()
sma_long = df [ "close" ] . rolling ( sma_long_period ) . mean ()
# Golden cross / Death cross
buy = ( sma_short > sma_long ) & ( sma_short . shift ( 1 ) <= sma_long . shift ( 1 ))
sell = ( sma_short < sma_long ) & ( sma_short . shift ( 1 ) >= sma_long . shift ( 1 ))
df [ "buy" ] = buy . fillna ( False ) . astype ( bool )
df [ "sell" ] = sell . fillna ( False ) . astype ( bool )
# Chart markers
buy_marks = [ df [ "low" ] . iloc [ i ] * 0.995 if df [ "buy" ] . iloc [ i ] else None for i in range ( len ( df ))]
sell_marks = [ df [ "high" ] . iloc [ i ] * 1.005 if df [ "sell" ] . iloc [ i ] else None for i in range ( len ( df ))]
output = {
"name" : my_indicator_name ,
"plots" : [
{ "name" : f "SMA { sma_short_period } " , "data" : sma_short . tolist (), "color" : "#FF9800" , "overlay" : True },
{ "name" : f "SMA { sma_long_period } " , "data" : sma_long . tolist (), "color" : "#3F51B5" , "overlay" : True }
],
"signals" : [
{ "type" : "buy" , "text" : "B" , "data" : buy_marks , "color" : "#00E676" },
{ "type" : "sell" , "text" : "S" , "data" : sell_marks , "color" : "#FF5252" }
]
}
```
#### Example: Using call_indicator()
```python
# Call another indicator by name or ID
# rsi_df = call_indicator('RSI', df) # By name
# rsi_df = call_indicator(5, df) # By ID
# rsi_df = call_indicator('RSI', df, {'period': 14}) # With params
# Note: The called indicator must be created first
# and accessible (own indicator or published community indicator)
```
### 🐛 Bug Fixes
#### Dashboard Fixes
- **Fixed current positions showing records from other users** - Position synchronization now correctly associates positions with the strategy owner's user_id
- **Fixed strategy distribution pie chart always showing "No Data"** - Chart now uses `strategy_stats` data which includes all strategies with trading activity
- **Removed AI strategy count from running strategies card** - Dashboard now only shows indicator strategy count since AI strategies category has been removed
---
2026-01-31 02:59:49 +08:00
## V2.1.1 (2026-01-31)
### 🚀 New Features
#### AI Analysis System Overhaul
- **Fast Analysis Mode**: Replaced the complex multi-agent system with a streamlined single LLM call architecture for faster and more accurate analysis
- **Progressive Loading**: Market data now loads independently - each section (sentiment, indices, heatmap, calendar) displays as soon as it's ready
- **Professional Loading Animation**: New progress bar with step indicators during AI analysis
- **Analysis Memory**: Store analysis results for history review and user feedback
- **Stop Loss/Take Profit Calculation**: Now based on ATR (Average True Range) and Support/Resistance levels with clear methodology hints
#### Global Market Integration
- Integrated Global Market data directly into AI Analysis page
- Real-time scrolling display of major global indices with flags, prices, and percentage changes
- Interactive heatmaps for Crypto, Commodities, Sectors, and Forex
- Economic calendar with bullish/bearish/neutral impact indicators
- Commodities heatmap added (Gold, Silver, Crude Oil, etc.)
#### Indicator Community Enhancements
- **Admin Review System**: Administrators can now review, approve, reject, unpublish, and delete community indicators
- **Purchase & Rating System**: Users can buy indicators, leave ratings and comments
- **Statistics Tracking**: Purchase count, average rating, rating count, view count for each indicator
#### Trading Assistant Improvements
- Improved IBKR/MT5 connection test feedback
- Added local deployment warning for external trading platforms
- Virtual profit/loss calculation for signal-only strategies
### 🐛 Bug Fixes
- Fixed progress bar and timer not animating during AI analysis
- Fixed missing i18n translations for various components
- Fixed Tiingo API rate limit issues with caching
2026-02-27 01:57:04 +08:00
- Fixed data fetching with multiple fallback sources
2026-01-31 02:59:49 +08:00
- Fixed watchlist price batch fetch timeout handling
- Fixed heatmap multi-language support for commodities and forex
2026-01-31 22:34:26 +08:00
- **Fixed AI analysis history not filtered by user** - All users were seeing the same history records; now each user only sees their own analysis history
- **Fixed "Missing Turnstile token" error when changing password** - Logged-in users no longer need Turnstile verification to request password change verification code
2026-01-31 02:59:49 +08:00
### 🎨 UI/UX Improvements
- Reorganized left menu: Indicator Market moved below Indicator Analysis, Settings moved to bottom
- Skeleton loading animations for progressive data display
- Dark theme support for all new components
- Compact market overview bar design
### 📋 Database Migration
**Run the following SQL on your PostgreSQL database before deploying V2.1.1:**
```sql
-- ============================================================
-- QuantDinger V2.1.1 Database Migration
-- ============================================================
-- 1. AI Analysis Memory Table
CREATE TABLE IF NOT EXISTS qd_analysis_memory (
id SERIAL PRIMARY KEY ,
market VARCHAR ( 50 ) NOT NULL ,
symbol VARCHAR ( 50 ) NOT NULL ,
decision VARCHAR ( 10 ) NOT NULL ,
confidence INT DEFAULT 50 ,
price_at_analysis DECIMAL ( 24 , 8 ),
entry_price DECIMAL ( 24 , 8 ),
stop_loss DECIMAL ( 24 , 8 ),
take_profit DECIMAL ( 24 , 8 ),
summary TEXT ,
reasons JSONB ,
risks JSONB ,
scores JSONB ,
indicators_snapshot JSONB ,
raw_result JSONB ,
created_at TIMESTAMP DEFAULT NOW (),
validated_at TIMESTAMP ,
actual_outcome VARCHAR ( 20 ),
actual_return_pct DECIMAL ( 10 , 4 ),
was_correct BOOLEAN ,
user_feedback VARCHAR ( 20 ),
feedback_at TIMESTAMP
);
-- Add raw_result column if table exists but column doesn't
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_analysis_memory' AND column_name = 'raw_result'
) THEN
ALTER TABLE qd_analysis_memory ADD COLUMN raw_result JSONB ;
END IF ;
END $$ ;
2026-01-31 22:34:26 +08:00
-- Add user_id column for user-specific history filtering
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_analysis_memory' AND column_name = 'user_id'
) THEN
ALTER TABLE qd_analysis_memory ADD COLUMN user_id INT ;
END IF ;
END $$ ;
2026-01-31 02:59:49 +08:00
CREATE INDEX IF NOT EXISTS idx_analysis_memory_symbol ON qd_analysis_memory ( market , symbol );
CREATE INDEX IF NOT EXISTS idx_analysis_memory_created ON qd_analysis_memory ( created_at DESC );
CREATE INDEX IF NOT EXISTS idx_analysis_memory_validated ON qd_analysis_memory ( validated_at ) WHERE validated_at IS NOT NULL ;
2026-01-31 22:34:26 +08:00
CREATE INDEX IF NOT EXISTS idx_analysis_memory_user ON qd_analysis_memory ( user_id );
2026-01-31 02:59:49 +08:00
-- 2. Indicator Purchase Records
CREATE TABLE IF NOT EXISTS qd_indicator_purchases (
id SERIAL PRIMARY KEY ,
indicator_id INTEGER NOT NULL REFERENCES qd_indicator_codes ( id ) ON DELETE CASCADE ,
buyer_id INTEGER NOT NULL REFERENCES qd_users ( id ) ON DELETE CASCADE ,
seller_id INTEGER NOT NULL REFERENCES qd_users ( id ),
price DECIMAL ( 10 , 2 ) NOT NULL DEFAULT 0 ,
created_at TIMESTAMP DEFAULT NOW (),
UNIQUE ( indicator_id , buyer_id )
);
CREATE INDEX IF NOT EXISTS idx_purchases_indicator ON qd_indicator_purchases ( indicator_id );
CREATE INDEX IF NOT EXISTS idx_purchases_buyer ON qd_indicator_purchases ( buyer_id );
CREATE INDEX IF NOT EXISTS idx_purchases_seller ON qd_indicator_purchases ( seller_id );
-- 3. Indicator Comments
CREATE TABLE IF NOT EXISTS qd_indicator_comments (
id SERIAL PRIMARY KEY ,
indicator_id INTEGER NOT NULL REFERENCES qd_indicator_codes ( id ) ON DELETE CASCADE ,
user_id INTEGER NOT NULL REFERENCES qd_users ( id ) ON DELETE CASCADE ,
rating INTEGER DEFAULT 5 CHECK ( rating >= 1 AND rating <= 5 ),
content TEXT DEFAULT '' ,
parent_id INTEGER REFERENCES qd_indicator_comments ( id ) ON DELETE CASCADE ,
is_deleted INTEGER DEFAULT 0 ,
created_at TIMESTAMP DEFAULT NOW (),
updated_at TIMESTAMP DEFAULT NOW ()
);
CREATE INDEX IF NOT EXISTS idx_comments_indicator ON qd_indicator_comments ( indicator_id );
CREATE INDEX IF NOT EXISTS idx_comments_user ON qd_indicator_comments ( user_id );
-- 4. Indicator Codes Extensions
DO $$
BEGIN
-- Purchase count
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'purchase_count'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN purchase_count INTEGER DEFAULT 0 ;
END IF ;
-- Average rating
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'avg_rating'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN avg_rating DECIMAL ( 3 , 2 ) DEFAULT 0 ;
END IF ;
-- Rating count
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'rating_count'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN rating_count INTEGER DEFAULT 0 ;
END IF ;
-- View count
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'view_count'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN view_count INTEGER DEFAULT 0 ;
END IF ;
-- Review status
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'review_status'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN review_status VARCHAR ( 20 ) DEFAULT 'approved' ;
UPDATE qd_indicator_codes SET review_status = 'approved' WHERE publish_to_community = 1 ;
END IF ;
-- Review note
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'review_note'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN review_note TEXT DEFAULT '' ;
END IF ;
-- Reviewed at
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'reviewed_at'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN reviewed_at TIMESTAMP ;
END IF ;
-- Reviewed by
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_indicator_codes' AND column_name = 'reviewed_by'
) THEN
ALTER TABLE qd_indicator_codes ADD COLUMN reviewed_by INTEGER ;
END IF ;
END $$ ;
CREATE INDEX IF NOT EXISTS idx_indicator_review_status ON qd_indicator_codes ( review_status );
-- 5. User Table Extensions
DO $$
BEGIN
-- Token version (for single-client login)
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_users' AND column_name = 'token_version'
) THEN
ALTER TABLE qd_users ADD COLUMN token_version INTEGER DEFAULT 1 ;
END IF ;
-- Notification settings
IF NOT EXISTS (
SELECT 1 FROM information_schema . columns
WHERE table_name = 'qd_users' AND column_name = 'notification_settings'
) THEN
ALTER TABLE qd_users ADD COLUMN notification_settings TEXT DEFAULT '{}' ;
END IF ;
END $$ ;
-- Migration Complete
DO $$
BEGIN
RAISE NOTICE '✅ QuantDinger V2.1.1 database migration completed!' ;
END $$ ;
```
### 🗑️ Removed
- Old multi-agent AI analysis system (`backend_api_python/app/services/agents/` directory)
- Old analysis routes and services
- Standalone Global Market page (merged into AI Analysis)
- Reflection worker background process
### ⚠️ Breaking Changes
- AI Analysis API endpoints changed from `/api/analysis/*` to `/api/fast-analysis/*`
- Old analysis history data is not compatible with new format
### 📝 Configuration Notes
- No new environment variables required
- Existing LLM configuration in System Settings will be used for AI Analysis
---
## Version History
| Version | Date | Highlights |
|---------|------|------------|
2026-03-01 03:42:10 +08:00
| V2.2.2 | 2026-02-28 | Polymarket prediction markets integration, AI-driven prediction analysis, asset trading recommendations |
2026-02-27 01:57:04 +08:00
| V2.2.1 | 2026-02-27 | Membership & Billing, USDT TRC20 payment, VIP free indicators, AI Trading Radar, simplified strategy creation |
| V2.1.3 | 2026-02-XX | Cross-sectional strategy support |
| V2.1.2 | 2026-02-01 | Indicator parameters, cross-indicator calling |
2026-01-31 02:59:49 +08:00
| V2.1.1 | 2026-01-31 | AI Analysis overhaul, Global Market integration, Indicator Community enhancements |
---
*For questions or issues, please open a GitHub issue or contact the maintainers.*