JoinQuant Quantitative Trading Platform — Provides A-share, futures, and fund data queries with event-driven strategy backtesting, supporting online research and live trading.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
JoinQuant Quantitative Trading Platform — Provides A-share, futures, and fund data queries with event-driven strategy backtesting, supporting online research and live trading.
homepage
https://www.joinquant.com
JoinQuant (聚宽量化)
JoinQuant is a leading Chinese online quantitative trading platform offering free data queries, strategy backtesting, and paper trading. It supports A-shares, futures, funds, indices, and more, using an event-driven Python strategy framework.
⚠️ Registration at https://www.joinquant.com is required. Strategies run on JoinQuant's cloud, but you can also retrieve data locally via JQData.
Installation (Local Data SDK)
pip install jqdatasdk
Local Data Authentication
import jqdatasdk as jq
# Log in with your JoinQuant account (free daily data quota)
jq.auth('your_username', 'your_password')
# Check remaining data quotaprint(jq.get_query_count())
Strategy Program Structure (Online Backtesting)
JoinQuant strategies use an event-driven architecture, written and run on the platform's web interface:
"""Initialization function — called once when the strategy starts"""
# Set benchmark index (CSI 300)
'000300.XSHG'
# Set commission and slippage
0
0.001
0.0003
0.0003
5
type
'stock'
0.02
# Set stock pool
'000001.XSHE'
def
handle_data
context, data
"""Intraday event — triggered once per trading frequency"""
# Get the last 20 days of closing prices
20
'1d'
'close'
'close'
5
'close'
# Golden cross — buy
if
0.9
# Death cross — sell
elif
0
Stock Code Format
Market
Suffix
Example
Shanghai A-shares
.XSHG
600000.XSHG (SPD Bank)
Shenzhen A-shares
.XSHE
000001.XSHE (Ping An Bank)
Indices
.XSHG/.XSHE
000300.XSHG (CSI 300)
Futures
.XDCE/.XZCE/.XSGE/.CCFX
IF2401.CCFX (Stock Index Futures)
Funds
.XSHG/.XSHE
510300.XSHG (CSI 300 ETF)
Data Query Functions (JQData)
Market Data
import jqdatasdk as jq
# Get daily candlestick data
df = jq.get_price(
'000001.XSHE', # Stock code
start_date='2024-01-01', # Start date
end_date='2024-06-30', # End date
frequency='daily', # Frequency: daily, minute, 1m, 5m, 15m, 30m, 60m, 120m
fields=['open', 'close', 'high', 'low', 'volume', 'money'],
skip_paused=True, # Skip suspended trading days
fq='pre', # Adjustment: None (unadjusted), 'pre' (forward-adjusted), 'post' (backward-adjusted)
panel=False# False returns DataFrame
)
# Get data for multiple stocks
df = jq.get_price(['000001.XSHE', '600000.XSHG'],
start_date='2024-01-01', end_date='2024-06-30',
frequency='daily', fields=['close'], panel=False)
# Get minute-level data
df = jq.get_price('000001.XSHE', start_date='2024-06-01 09:30:00',
end_date='2024-06-01 15:00:00', frequency='1m')
Get Last N Data Points
# Get closing prices for the last 20 trading days
df = jq.get_bars('000001.XSHE', count=20, unit='1d', fields=['close', 'volume'])
Financial Data
# Query financial indicators
df = jq.get_fundamentals(
jq.query(
jq.valuation.code,
jq.valuation.market_cap, # Total market cap (100M CNY)
jq.valuation.pe_ratio, # Price-to-earnings ratio
jq.valuation.pb_ratio, # Price-to-book ratio
jq.valuation.turnover_ratio, # Turnover rate
jq.indicator.roe, # Return on equity (ROE)
jq.indicator.eps, # Earnings per share
jq.indicator.revenue, # Revenue
jq.indicator.net_profit, # Net profit
).filter(
jq.valuation.pe_ratio > 0, # Filter out loss-making stocks
jq.valuation.pe_ratio < 30, # PE less than 30
jq.valuation.market_cap > 100# Market cap greater than 10B CNY
).order_by(
jq.valuation.market_cap.desc() # Sort by market cap descending
).limit(50), # Take top 50
date='2024-06-30'
)
print(df)
Index Constituents
# Get CSI 300 constituents
stocks = jq.get_index_stocks('000300.XSHG')
print(f'CSI 300 has {len(stocks)} constituent stocks')
# Get industry constituents
stocks = jq.get_industry_stocks('I64') # Banking
Industry Classification
# Get the industry a stock belongs to
industry = jq.get_industry('000001.XSHE')
print(industry)
# Get Shenwan Level-1 industry list
industries = jq.get_industries(name='sw_l1')
print(industries)
Trading Calendar
# Get list of trading days
days = jq.get_trade_days(start_date='2024-01-01', end_date='2024-06-30')
# Get all trading days
all_days = jq.get_all_trade_days()
Stock Basic Information
# Get all A-share listings
stocks = jq.get_all_securities(types=['stock'], date='2024-06-30')
print(f'Total A-shares: {len(stocks)}')
# Get info for a single stock
info = jq.get_security_info('000001.XSHE')
print(f'Name: {info.display_name}, Listing date: {info.start_date}')
# Get ST stocks
st_stocks = jq.get_extras('is_st', ['000001.XSHE'], start_date='2024-01-01', end_date='2024-06-30')
Top Trader (Dragon & Tiger) List Data
# Get Dragon & Tiger list data
df = jq.get_billboard_list(stock_list=None, start_date='2024-06-01', end_date='2024-06-30')
print(df.head())
Margin Trading Data
# Get margin trading summary data
df = jq.get_mtss('000001.XSHE', start_date='2024-01-01', end_date='2024-06-30')
print(df.head())
# Rebalance to target quantity
order_target('000001.XSHE', 1000) # Adjust to hold 1000 shares
order_target('000001.XSHE', 0) # Liquidate position# Rebalance to target value
order_target_value('000001.XSHE', 100000) # Adjust to 100,000 CNY market value# Rebalance to target percentage (of total assets)
order_target_percent('000001.XSHE', 0.3) # Adjust to 30% of total assets
Cancel Order
# Get unfilled orders
open_orders = get_open_orders()
# Cancel a specific order
cancel_order(order_id)
Account & Position Queries
defhandle_data(context, data):
# Account information
cash = context.portfolio.available_cash # Available cash
total = context.portfolio.total_value # Total assets
positions_value = context.portfolio.positions_value # Position market value# Query positionsfor stock, pos in context.portfolio.positions.items():
print(f'{stock}: Quantity={pos.total_amount}, 'f'Sellable={pos.closeable_amount}, 'f'Cost={pos.avg_cost:.2f}, 'f'Current price={pos.price:.2f}, 'f'Market value={pos.value:.2f}')
Scheduled Tasks
definitialize(context):
# Execute before market open each day
run_daily(before_market_open, time='before_open')
# Execute at specified time each day
run_daily(market_open, time='09:35')
run_daily(afternoon_check, time='14:50')
# Execute weekly
run_weekly(weekly_rebalance, weekday=1, time='09:35') # Every Monday# Execute monthly
run_monthly(monthly_rebalance, monthday=1, time='09:35') # 1st of each monthdefbefore_market_open(context):
log.info('Pre-market preparation')
defmarket_open(context):
log.info('Market open trading')
Risk Management
definitialize(context):
g.security = '000001.XSHE'
set_benchmark('000300.XSHG')
defhandle_data(context, data):
security = g.security
# Get current price
current_price = data[security].close
# Check position P&Lif security in context.portfolio.positions:
pos = context.portfolio.positions[security]
cost = pos.avg_cost
pnl_ratio = (current_price - cost) / cost
# Take profit at 10%if pnl_ratio >= 0.10:
order_target(security, 0)
log.info(f'Take profit: {security} gain {pnl_ratio:.2%}')
# Stop loss at 5%elif pnl_ratio <= -0.05:
order_target(security, 0)
log.info(f'Stop loss: {security} loss {pnl_ratio:.2%}')
Full Example — Multi-Factor Stock Selection Strategy
definitialize(context):
set_benchmark('000300.XSHG')
set_order_cost(OrderCost(open_tax=0, close_tax=0.001,
open_commission=0.0003, close_commission=0.0003,
min_commission=5), type='stock')
g.hold_num = 10# Number of holdings# Rebalance on the 1st trading day of each month
run_monthly(rebalance, monthday=1, time='09:35')
defrebalance(context):
# Multi-factor stock selection
df = get_fundamentals(
query(
valuation.code,
valuation.pe_ratio,
valuation.pb_ratio,
valuation.market_cap,
indicator.roe,
).filter(
valuation.pe_ratio > 5,
valuation.pe_ratio < 25,
valuation.pb_ratio > 0.5,
valuation.pb_ratio < 5,
indicator.roe > 10,
valuation.market_cap > 100,
).order_by(
valuation.pe_ratio.asc()
).limit(g.hold_num)
)
target_stocks = list(df['code'])
log.info(f'Selected {len(target_stocks)} stocks')
# Sell stocks not in the target listfor stock in context.portfolio.positions:
if stock notin target_stocks:
order_target(stock, 0)
# Equal-weight buy target stocksif target_stocks:
per_value = context.portfolio.total_value * 0.95 / len(target_stocks)
for stock in target_stocks:
order_target_value(stock, per_value)
defhandle_data(context, data):
pass
Advanced Examples
Sector Rotation Strategy
definitialize(context):
set_benchmark('000300.XSHG')
g.hold_num = 5
g.industry_etfs = {
'512010.XSHG': '医药ETF',
'512880.XSHG': '证券ETF',
'512800.XSHG': '银行ETF',
'515030.XSHG': '新能源车ETF',
'159995.XSHE': '芯片ETF',
'512690.XSHG': '白酒ETF',
'510300.XSHG': '沪深300ETF',
'159915.XSHE': '创业板ETF',
}
run_monthly(rebalance, monthday=1, time='09:35')
defrebalance(context):
"""Sort by 20-day momentum, select the top N strongest ETFs"""
momentum = {}
for etf, name in g.industry_etfs.items():
df = attribute_history(etf, 20, '1d', ['close'])
iflen(df) >= 20:
ret = (df['close'].iloc[-1] / df['close'].iloc[0]) - 1
momentum[etf] = ret
# Sort by momentum
sorted_etfs = sorted(momentum.items(), key=lambda x: x[1], reverse=True)
targets = [etf for etf, _ in sorted_etfs[:g.hold_num]]
log.info(f'This month selected: {[g.industry_etfs[e] for e in targets]}')
# Sell positions not in the target listfor stock in context.portfolio.positions:
if stock notin targets:
order_target(stock, 0)
# Equal-weight buy
per_value = context.portfolio.total_value * 0.95 / len(targets)
for etf in targets:
order_target_value(etf, per_value)
defhandle_data(context, data):
pass