0
# Framework Core
1
2
Strategy context, execution framework, and event system providing the foundation for strategy development and lifecycle management. The core framework handles strategy execution phases, event processing, global state management, and provides the runtime environment for trading strategies.
3
4
## Capabilities
5
6
### Strategy Context
7
8
The central context object available to all strategy functions, providing access to portfolio, accounts, market data, and system state.
9
10
```python { .api }
11
class StrategyContext:
12
"""
13
Strategy context object (exposed as 'context' in strategies).
14
15
Properties:
16
- portfolio (Portfolio): Main portfolio object with all accounts and positions
17
- stock_account (Account): Stock trading account
18
- future_account (Account): Futures trading account
19
- bond_account (Account): Bond trading account
20
- now (datetime): Current strategy execution time
21
- universe (list[str]): Current strategy universe of instruments
22
- run_info (RunInfo): Strategy run information and metadata
23
- config (dict): Strategy configuration
24
25
Available in strategy functions as global 'context' variable.
26
"""
27
```
28
29
### Global Variables
30
31
Global variable namespace for user data persistence across strategy execution.
32
33
```python { .api }
34
# Global variables namespace (available as 'g' in strategies)
35
g = GlobalVars() # User namespace for storing custom data
36
37
# Usage in strategies:
38
def init(context):
39
g.my_variable = "some_value"
40
g.counters = {"buy": 0, "sell": 0}
41
42
def handle_bar(context, bar_dict):
43
g.counters["buy"] += 1
44
logger.info(f"My variable: {g.my_variable}")
45
```
46
47
### Event System
48
49
Event publishing and subscription system for strategy and system events.
50
51
```python { .api }
52
def subscribe_event(event_type, handler):
53
"""
54
Subscribe to system events.
55
56
Parameters:
57
- event_type (EVENT): Event type to subscribe to
58
- handler (callable): Event handler function
59
60
Returns:
61
None
62
63
The handler function receives (context, event_data) parameters.
64
"""
65
66
class Event:
67
"""
68
Event object for system messaging.
69
70
Properties:
71
- event_type (EVENT): Type of event
72
- timestamp (datetime): Event timestamp
73
- data (dict): Event-specific data
74
"""
75
76
class EventBus:
77
"""
78
Event publishing and subscription system.
79
80
Methods:
81
- publish_event(event): Publish event to subscribers
82
- add_listener(event_type, handler): Add event listener
83
- remove_listener(event_type, handler): Remove event listener
84
"""
85
```
86
87
### Strategy Execution Management
88
89
Core classes managing strategy lifecycle and execution phases.
90
91
```python { .api }
92
class Strategy:
93
"""
94
Strategy execution engine and lifecycle manager.
95
96
Methods:
97
- init(): Initialize strategy
98
- before_trading(): Pre-market phase
99
- open_auction(): Opening auction phase
100
- handle_bar(bar_dict): Process bar data
101
- handle_tick(tick): Process tick data
102
- after_trading(): Post-market phase
103
- teardown(): Strategy cleanup
104
"""
105
106
class ExecutionContext:
107
"""
108
Execution context and phase enforcement.
109
110
Properties:
111
- phase (EXECUTION_PHASE): Current execution phase
112
- strategy_context (StrategyContext): Strategy context
113
-
114
Methods:
115
- set_phase(phase): Set current execution phase
116
- enforce_phase(allowed_phases): Enforce phase restrictions
117
"""
118
119
class Executor:
120
"""
121
Strategy executor and orchestrator.
122
123
Methods:
124
- run(): Execute complete strategy
125
- execute_phase(phase): Execute specific phase
126
- handle_exception(exception): Handle strategy exceptions
127
"""
128
```
129
130
### Strategy Loading
131
132
Strategy loading interfaces for different strategy sources.
133
134
```python { .api }
135
class FileStrategyLoader:
136
"""
137
Load strategy from Python file.
138
139
Methods:
140
- load(file_path): Load strategy from file path
141
- get_strategy_functions(): Extract strategy functions
142
"""
143
144
class SourceCodeStrategyLoader:
145
"""
146
Load strategy from source code string.
147
148
Methods:
149
- load(source_code): Load strategy from code string
150
- compile_strategy(): Compile strategy code
151
"""
152
153
class UserFuncStrategyLoader:
154
"""
155
Load strategy from user-defined functions.
156
157
Methods:
158
- load(user_funcs): Load from function dictionary
159
- validate_functions(): Validate function signatures
160
"""
161
```
162
163
### Run Information
164
165
Metadata and information about strategy execution.
166
167
```python { .api }
168
class RunInfo:
169
"""
170
Strategy run information and metadata.
171
172
Properties:
173
- start_date (date): Strategy start date
174
- end_date (date): Strategy end date
175
- frequency (str): Data frequency
176
- run_type (RUN_TYPE): Execution mode
177
- benchmark (str): Benchmark instrument
178
- matching_type (MATCHING_TYPE): Order matching type
179
- commission_multiplier (float): Commission multiplier
180
- margin_multiplier (float): Margin multiplier
181
- slippage (float): Slippage factor
182
- accounts (dict): Account configurations
183
"""
184
```
185
186
### Environment Singleton
187
188
Global environment singleton managing system state.
189
190
```python { .api }
191
class Environment:
192
"""
193
Global environment singleton for system state.
194
195
Properties:
196
- config (dict): System configuration
197
- data_proxy (DataProxy): Data access layer
198
- broker (AbstractBroker): Order execution broker
199
- portfolio (Portfolio): Portfolio manager
200
- event_bus (EventBus): Event system
201
- phase (EXECUTION_PHASE): Current execution phase
202
203
Methods:
204
- get_instance(): Get singleton instance
205
- set_instance(env): Set singleton instance
206
"""
207
```
208
209
## Framework Usage Examples
210
211
### Strategy Function Definition
212
213
```python
214
# Strategy functions with framework integration
215
def init(context):
216
"""Strategy initialization - called once at start."""
217
# Access context properties
218
logger.info(f"Strategy start date: {context.run_info.start_date}")
219
logger.info(f"Initial portfolio value: {context.portfolio.total_value}")
220
221
# Set up global variables
222
g.trade_count = 0
223
g.last_rebalance = None
224
225
# Configure universe
226
context.stocks = ["000001.XSHE", "000002.XSHE"]
227
update_universe(context.stocks)
228
229
def before_trading(context):
230
"""Pre-market phase - called daily before market open."""
231
logger.info(f"Before trading on {context.now.date()}")
232
233
# Daily preparation logic
234
g.daily_signals = calculate_signals(context)
235
236
# Check for rebalancing
237
if should_rebalance(context):
238
g.rebalance_today = True
239
else:
240
g.rebalance_today = False
241
242
def handle_bar(context, bar_dict):
243
"""Bar processing - called for each bar."""
244
# Access current market data
245
for stock_id, bar in bar_dict.items():
246
current_price = bar.close
247
248
# Strategy logic using global variables
249
if g.rebalance_today and stock_id in g.daily_signals:
250
signal = g.daily_signals[stock_id]
251
target_weight = signal * 0.1 # 10% max per stock
252
order_target_percent(stock_id, target_weight)
253
g.trade_count += 1
254
255
def after_trading(context):
256
"""Post-market phase - called daily after market close."""
257
logger.info(f"After trading on {context.now.date()}")
258
logger.info(f"Portfolio value: {context.portfolio.total_value:.2f}")
259
logger.info(f"Total trades today: {g.trade_count}")
260
261
# Reset daily variables
262
g.rebalance_today = False
263
```
264
265
### Event System Usage
266
267
```python
268
from rqalpha.apis import subscribe_event, EVENT
269
270
def init(context):
271
# Subscribe to various events
272
subscribe_event(EVENT.TRADE, on_trade)
273
subscribe_event(EVENT.ORDER_CREATION_PASS, on_order_created)
274
subscribe_event(EVENT.ORDER_CREATION_REJECT, on_order_rejected)
275
subscribe_event(EVENT.SETTLEMENT, on_settlement)
276
277
g.trade_history = []
278
g.order_history = []
279
280
def on_trade(context, trade):
281
"""Handle trade execution events."""
282
logger.info(f"Trade executed: {trade.instrument.symbol} "
283
f"{trade.last_quantity} @ {trade.last_price}")
284
285
# Store trade information
286
trade_info = {
287
"datetime": trade.datetime,
288
"instrument": trade.order_book_id,
289
"quantity": trade.last_quantity,
290
"price": trade.last_price,
291
"side": trade.side,
292
"commission": trade.commission
293
}
294
g.trade_history.append(trade_info)
295
296
def on_order_created(context, order):
297
"""Handle successful order creation."""
298
logger.info(f"Order created: {order.order_id} for {order.instrument.symbol}")
299
300
order_info = {
301
"order_id": order.order_id,
302
"instrument": order.order_book_id,
303
"quantity": order.quantity,
304
"price": order.price,
305
"status": order.status,
306
"created_at": order.created_at
307
}
308
g.order_history.append(order_info)
309
310
def on_order_rejected(context, order):
311
"""Handle order rejection."""
312
logger.warning(f"Order rejected: {order.order_id}")
313
# Implement rejection handling logic
314
315
def on_settlement(context, settlement_data):
316
"""Handle daily settlement."""
317
logger.info("Daily settlement completed")
318
# Daily cleanup or reporting logic
319
```
320
321
### Global Variables Management
322
323
```python
324
def init(context):
325
# Initialize global variables
326
g.indicators = {}
327
g.signals = {}
328
g.position_history = []
329
g.performance_metrics = {
330
"max_drawdown": 0.0,
331
"peak_value": 0.0,
332
"win_rate": 0.0,
333
"trades": []
334
}
335
336
def handle_bar(context, bar_dict):
337
# Update indicators using global variables
338
for stock_id in context.universe:
339
if stock_id not in g.indicators:
340
g.indicators[stock_id] = {
341
"sma_20": [],
342
"sma_60": [],
343
"rsi": []
344
}
345
346
# Calculate indicators
347
price_history = history_bars(stock_id, 60, "1d", fields="close")
348
sma_20 = price_history["close"][-20:].mean()
349
sma_60 = price_history["close"][-60:].mean()
350
351
# Store in global variables
352
g.indicators[stock_id]["sma_20"].append(sma_20)
353
g.indicators[stock_id]["sma_60"].append(sma_60)
354
355
# Keep only recent values
356
if len(g.indicators[stock_id]["sma_20"]) > 252:
357
g.indicators[stock_id]["sma_20"] = g.indicators[stock_id]["sma_20"][-252:]
358
g.indicators[stock_id]["sma_60"] = g.indicators[stock_id]["sma_60"][-252:]
359
360
# Generate signals
361
if sma_20 > sma_60:
362
g.signals[stock_id] = 1 # Buy signal
363
else:
364
g.signals[stock_id] = -1 # Sell signal
365
366
def after_trading(context):
367
# Update performance metrics in global variables
368
current_value = context.portfolio.total_value
369
370
if current_value > g.performance_metrics["peak_value"]:
371
g.performance_metrics["peak_value"] = current_value
372
373
drawdown = (g.performance_metrics["peak_value"] - current_value) / g.performance_metrics["peak_value"]
374
if drawdown > g.performance_metrics["max_drawdown"]:
375
g.performance_metrics["max_drawdown"] = drawdown
376
377
# Store daily position snapshot
378
position_snapshot = {
379
"date": context.now.date(),
380
"total_value": current_value,
381
"cash": context.portfolio.cash,
382
"positions": {pos.order_book_id: pos.quantity for pos in get_positions()}
383
}
384
g.position_history.append(position_snapshot)
385
```
386
387
### Context Properties Access
388
389
```python
390
def handle_bar(context, bar_dict):
391
# Portfolio information
392
logger.info(f"Portfolio total value: {context.portfolio.total_value}")
393
logger.info(f"Available cash: {context.portfolio.cash}")
394
logger.info(f"Market value: {context.portfolio.market_value}")
395
396
# Account-specific information
397
stock_cash = context.stock_account.cash
398
stock_value = context.stock_account.total_value
399
future_cash = context.future_account.cash
400
401
logger.info(f"Stock account - Cash: {stock_cash}, Value: {stock_value}")
402
logger.info(f"Future account cash: {future_cash}")
403
404
# Current time and universe
405
logger.info(f"Current time: {context.now}")
406
logger.info(f"Universe size: {len(context.universe)}")
407
408
# Run information
409
logger.info(f"Frequency: {context.run_info.frequency}")
410
logger.info(f"Benchmark: {context.run_info.benchmark}")
411
412
# Configuration access
413
start_date = context.config["base"]["start_date"]
414
accounts = context.config["base"]["accounts"]
415
logger.info(f"Strategy period: {start_date} to {context.run_info.end_date}")
416
```
417
418
### Custom Helper Functions
419
420
```python
421
def init(context):
422
# Define helper functions in global scope
423
g.calculate_rsi = create_rsi_calculator()
424
g.calculate_bollinger = create_bollinger_calculator()
425
g.risk_manager = RiskManager(context.portfolio.total_value)
426
427
def create_rsi_calculator():
428
"""Create RSI calculation function."""
429
def calculate_rsi(prices, period=14):
430
deltas = np.diff(prices)
431
seed = deltas[:period+1]
432
up = seed[seed >= 0].sum() / period
433
down = -seed[seed < 0].sum() / period
434
rs = up / down
435
rsi = np.zeros_like(prices)
436
rsi[:period] = 100. - 100. / (1. + rs)
437
438
for i in range(period, len(prices)):
439
delta = deltas[i-1]
440
if delta > 0:
441
upval = delta
442
downval = 0.
443
else:
444
upval = 0.
445
downval = -delta
446
447
up = (up * (period - 1) + upval) / period
448
down = (down * (period - 1) + downval) / period
449
rs = up / down
450
rsi[i] = 100. - 100. / (1. + rs)
451
452
return rsi
453
return calculate_rsi
454
455
class RiskManager:
456
"""Custom risk management class."""
457
def __init__(self, initial_capital):
458
self.initial_capital = initial_capital
459
self.max_position_size = 0.1 # 10% max per position
460
self.max_drawdown = 0.2 # 20% max drawdown
461
462
def check_position_size(self, portfolio_value, position_value):
463
"""Check if position size exceeds limits."""
464
position_weight = position_value / portfolio_value
465
return position_weight <= self.max_position_size
466
467
def check_drawdown(self, current_value, peak_value):
468
"""Check if drawdown exceeds limits."""
469
drawdown = (peak_value - current_value) / peak_value
470
return drawdown <= self.max_drawdown
471
472
def handle_bar(context, bar_dict):
473
# Use custom helper functions
474
for stock_id in context.universe:
475
price_history = history_bars(stock_id, 30, "1d", fields="close")
476
rsi = g.calculate_rsi(price_history["close"])[-1]
477
478
# Risk management check
479
portfolio_value = context.portfolio.total_value
480
if stock_id in context.portfolio.positions:
481
position_value = context.portfolio.positions[stock_id].market_value
482
if not g.risk_manager.check_position_size(portfolio_value, position_value):
483
logger.warning(f"Position size limit exceeded for {stock_id}")
484
continue
485
486
# Trading logic with RSI
487
if rsi < 30: # Oversold
488
order_target_percent(stock_id, 0.05) # 5% allocation
489
elif rsi > 70: # Overbought
490
order_target_percent(stock_id, 0) # Close position
491
```