| name | ptrade-dev |
| version | 1.0.0 |
| description | PTrade/SimTradeLab strategy development guardrails. Auto-loads PTrade API reference,
enforces platform constraints (no f-string, no import io/sys), validates lifecycle
function usage, and prevents common API misuse. Use when writing, editing, or reviewing
any PTrade strategy code or SimTradeLab backtest code.
TRIGGER: when editing files in strategies/, src/simtradelab/ptrade/, or any .py file
that imports from simtradelab or uses PTrade API functions (initialize, handle_data,
set_universe, get_history, order, etc).
|
| allowed-tools | ["Read","Edit","Write","Bash","Grep","Glob"] |
PTrade Strategy Development Skill
You are writing code for the PTrade quantitative trading platform or its local simulator SimTradeLab.
This skill ensures you NEVER make API errors by providing the complete reference inline.
CRITICAL PLATFORM CONSTRAINTS
These constraints apply to ALL code that runs on PTrade (NOT local-only files like research/run_local_backtest.py):
-
NO f-strings — Use % formatting or .format(). PTrade's Python does not support f-strings.
log.info(f"price: {price}")
log.info("price: %s" % price)
log.info("price: {}".format(price))
-
NO import io or import sys — These modules are blocked on PTrade.
-
NO walrus operator := — Not supported.
-
NO match/case — Not supported.
-
Code format: PTrade uses .SS (Shanghai) and .SZ (Shenzhen) suffixes, but Order objects return .XSHG / .XSHE suffixes. Be aware of this difference.
-
Global object g: Use g.xxx for cross-function state. Variables starting with __ are private and won't be persisted.
-
log object: Use log.info(), log.warning(), log.error() etc. Never print().
STRATEGY LIFECYCLE (MANDATORY KNOWLEDGE)
A strategy has exactly 2 required functions and 5 optional ones:
initialize(context) # REQUIRED — runs once at startup
handle_data(context, data) # REQUIRED — runs every bar (daily/minute)
before_trading_start(context, data) # optional — runs before market open
after_trading_end(context, data) # optional — runs after market close
tick_data(context, data) # optional — runs every 3s (live trading only)
on_order_response(context, order_list) # optional — order callback (live only)
on_trade_response(context, trade_list) # optional — trade callback (live only)
Lifecycle Timing
- initialize: runs ONCE at strategy start
- before_trading_start: backtest 8:30, live 9:10 (configurable)
- handle_data: backtest 9:31-15:00 (minute) or 15:00 (daily); live 9:30-14:59
- after_trading_end: ~15:30
- tick_data: 9:30-14:59, every 3s (live only)
API FUNCTION LIFECYCLE RESTRICTIONS
CRITICAL: Each API can ONLY be called from specific lifecycle functions. Calling from the wrong function will error.
initialize-ONLY APIs (setup functions)
set_benchmark(benchmark) # Set benchmark index
set_commission(commission) # Set commission (backtest only)
set_fixed_slippage(slippage) # Set fixed slippage (backtest only)
set_slippage(slippage) # Set slippage (backtest only)
set_volume_ratio(ratio) # Set volume ratio (backtest only)
set_limit_mode(mode) # Set limit mode (backtest only)
set_yesterday_position(positions) # Set initial positions (backtest only)
set_parameters(params) # Set strategy params
run_daily(func, time) # Schedule daily function
run_interval(func, interval) # Schedule interval function (live only)
set_future_commission(commission) # Futures commission (backtest only)
set_margin_rate(security, rate) # Futures margin (backtest/live)
permission_test(account, end_date)# Permission check (live only)
create_dir(user_path) # Create directory (live only)
handle_data / tick_data APIs (trading functions)
set_universe(securities) # Set/update stock pool (also in initialize/before_trading_start)
order(security, amount, limit_price=None) # Buy/sell by amount
order_target(security, target_amount, limit_price=None) # Target amount
order_value(security, value, limit_price=None) # Buy/sell by value
order_target_value(security, target_value, limit_price=None) # Target value
order_market(security, amount) # Market order (live only)
cancel_order(order_id) # Cancel order (also in on_order_response)
cancel_order_ex(order_id) # Cancel order extended (live)
order_tick(security, amount, limit_price, tick_type) # Tick order (live only)
get_snapshot(security_list) # Realtime snapshot (live only)
get_gear_price(security_list) # Level quotes (live only)
after_trading_end APIs
after_trading_order(security, amount, limit_price) # After-hours order (live)
after_trading_cancel_order(order_id) # Cancel after-hours (live)
get_trades_file() # Get trade file (backtest)
get_deliver(start_date, end_date) # Delivery records (live)
get_fundjour(start_date, end_date) # Fund journal (live)
send_email(...) # Send email (live, also in on_order/on_trade_response)
send_qywx(...) # Send WeChat (live, also in on_order/on_trade_response)
Universal APIs (callable from ANY lifecycle function)
# Market data
get_history(count, frequency, field, security_list, fq, include, fill, is_dict, start_date, end_date)
get_price(security, start_date, end_date, frequency, fields, count)
# Trading info
get_position(security) # Get position for one stock
get_positions(security_list) # Get positions for multiple stocks
get_open_orders(security=None) # Get pending orders
get_order(order_id) # Get specific order
get_orders(security=None) # Get all orders today
get_trades(security=None) # Get trades today
# Stock info
get_stock_name(security_list)
get_stock_info(security_list)
get_stock_status(security_list)
get_stock_exrights(security_list)
get_stock_blocks(security_list)
get_index_stocks(index_code)
get_industry_stocks(industry_code)
get_fundamentals(stocks, table, fields, date)
get_Ashares(date)
check_limit(security, query_date=None)
# Date/Calendar
get_trading_day(day=0)
get_all_trades_days(date=None)
get_trade_days(start_date, end_date)
# Technical indicators
get_MACD(close, short=12, long=26, m=9)
get_KDJ(high, low, close, n=9, m1=3, m2=3)
get_RSI(close, n=6)
get_CCI(high, low, close, n=14)
# Utility
log.info/warning/error/debug/critical
is_trade() # True if live trading
get_user_name()
get_research_path()
KEY OBJECTS REFERENCE
context.portfolio (Portfolio)
context.portfolio.cash
context.portfolio.positions
context.portfolio.portfolio_value
context.portfolio.positions_value
context.portfolio.capital_used
context.portfolio.returns
context.portfolio.pnl
context.portfolio.start_date
Position (stock)
pos = context.portfolio.positions[code]
pos.sid
pos.amount
pos.enable_amount
pos.last_sale_price
pos.cost_basis
pos.today_amount
pos.business_type
data (in handle_data)
bar = data[security]
bar['open']
bar['close']
bar['high']
bar['low']
bar['volume']
bar['money']
bar['price']
bar['dt']
Order object
order_obj.id
order_obj.dt
order_obj.limit
order_obj.symbol
order_obj.amount
context.blotter
context.blotter.current_dt
get_history DETAILED REFERENCE
This is the MOST commonly misused API. Pay close attention:
get_history(
count,
frequency='1d',
field='close',
security_list=None,
fq=None,
include=False,
fill='nan',
is_dict=False,
start_date=None,
end_date=None
)
Return type varies:
- Single field + single stock:
pd.DataFrame with column = field name
- Single field + multiple stocks:
pd.DataFrame with columns = stock codes
- Multiple fields +
is_dict=False: PanelLike object (dict-like, key=field)
- Multiple fields +
is_dict=True: dict of DataFrames
Common patterns:
df = get_history(20, '1d', 'close', '600570.SS', fq='pre', include=False)
ma20 = df['close'].mean()
data = get_history(20, '1d', ['open','high','low','close','volume'], '600570.SS', fq='pre')
closes = data['close']['600570.SS']
df = get_history(20, '1d', 'close', ['600570.SS', '000001.SZ'])
get_price DETAILED REFERENCE
get_price(
security,
start_date=None,
end_date=None,
frequency='1d',
fields=None,
count=None
)
Returns: pd.DataFrame with DatetimeIndex, columns = requested fields
COMMON MISTAKES TO PREVENT
- Calling
order() in initialize() — Trading functions only work in handle_data/tick_data
- Using
set_commission() in handle_data() — Setup functions only work in initialize()
- Assuming
data[security] always exists — Only stocks in set_universe() are in data
- Forgetting T+1 rule —
pos.enable_amount may be 0 for stocks bought today; always check before selling
- Using
.XSHG/.XSHE codes with order() — Use .SS/.SZ format for orders
- Calling
get_snapshot() in backtest — Only available in live trading
- Using f-strings — PTrade does NOT support f-strings!
get_history with include=True — Current bar data may be incomplete
- Negative amount in
order() — Negative = sell, positive = buy
SIMTRADELAB LOCAL-ONLY DIFFERENCES
When writing code for SimTradeLab local backtest (research/run_local_backtest.py):
- f-strings ARE allowed (local Python 3.9+)
import io/sys ARE allowed
- Data comes from local parquet/CSV files via DataContext
- API behavior is simulated to match PTrade as closely as possible
SELF-CHECK BEFORE SUBMITTING CODE
Before finishing any PTrade strategy code, verify: