Skip to content

Commit 19021a2

Browse files
fix bug (#957)
* fix bug * update * update * update * update * add split test case * update --------- Co-authored-by: Don <[email protected]>
1 parent 794d4fd commit 19021a2

File tree

4 files changed

+124
-6
lines changed

4 files changed

+124
-6
lines changed

rqalpha/data/bundle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def __call__(self):
128128
if split is None:
129129
raise RuntimeError("Got no split data")
130130
split['split_factor'] = split['split_coefficient_to'] / split['split_coefficient_from']
131-
split = split[['split_factor']]
131+
split = split[['split_factor', 'split_coefficient_to', 'split_coefficient_from']]
132132
split.reset_index(inplace=True)
133133
split.rename(columns={'ex_dividend_date': 'ex_date'}, inplace=True) # type: ignore
134134
split['ex_date'] = [convert_date_to_int(d) for d in split['ex_date']]

rqalpha/mod/rqalpha_mod_sys_accounts/position_model.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
from typing import Optional, Deque, Tuple
1919
from collections import deque
2020

21-
from decimal import Decimal
22-
from numpy import ndarray
21+
from decimal import Decimal, ROUND_HALF_UP
22+
from numpy import ndarray, isclose
2323

2424
from rqalpha.interface import TransactionCost
2525
from rqalpha.model.trade import Trade
@@ -262,17 +262,32 @@ def _handle_dividend_payable(self, trading_date: date) -> float:
262262
return payable_value - amount * last_price
263263
else:
264264
return payable_value
265+
266+
def _get_split_ratio(self, splits) -> Decimal:
267+
# rqalpha 6.1.0 修改了 bundle 的 splits_factor 的数据格式,需要向前兼容
268+
if 'split_coefficient_to' not in splits.dtype.names:
269+
return Decimal(splits["split_factor"].cumprod()[-1])
270+
271+
for field in ["split_coefficient_to", "split_coefficient_from"]:
272+
if not all(isclose(splits[field] % 1, 0)):
273+
ratio = splits["split_coefficient_to"] / splits["split_coefficient_from"]
274+
return Decimal(ratio.cumprod[-1])
275+
276+
coefficient_to = (splits["split_coefficient_to"].astype(int)).cumprod()[-1]
277+
coefficient_from = (splits["split_coefficient_from"].astype(int)).cumprod()[-1]
278+
return Decimal(int(coefficient_to)) / Decimal(int(coefficient_from))
265279

266280
def _handle_split(self, trading_date, data_proxy) -> float:
267281
splits = self._get_dividends_or_splits(self._all_splits, trading_date, "ex_date") # type: ignore[reportIncompatibleVariableOverride]
268282
if splits is None or len(splits) == 0:
269283
return 1.
270-
ratio: float = splits["split_factor"].cumprod()[-1]
284+
ratio_decimal = self._get_split_ratio(splits)
285+
286+
ratio = float(ratio_decimal)
271287
self._avg_price /= ratio
272288
self._last_price /= ratio # type: ignore
273-
ratio_decimal = Decimal(ratio)
274289
# int(6000 * 1.15) -> 6899
275-
self._old_quantity = self._quantity = round(Decimal(self._quantity) * ratio_decimal)
290+
self._old_quantity = self._quantity = int((Decimal(self._quantity) * ratio_decimal).quantize(Decimal("1"), rounding=ROUND_HALF_UP))
276291
self._queue.handle_split(ratio_decimal, self._quantity)
277292
return ratio
278293

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[trades]
2+
DataFrame
3+
{"shape":[0,0],"dtypes":{},"index_dtype":"int64","index_name":null,"columns":[]}
4+
# Empty DataFrame
5+
6+
[stock_positions]
7+
DataFrame
8+
{"shape":[8,6],"dtypes":{"order_book_id":"object","symbol":"object","quantity":"float64","last_price":"float64","avg_price":"float64","market_value":"float64"},"index_dtype":"datetime64[ns]","index_name":"date","columns":["order_book_id","symbol","quantity","last_price","avg_price","market_value"]}
9+
,order_book_id,symbol,quantity,last_price,avg_price,market_value
10+
2024-06-11 00:00:00,688550.XSHG,瑞联新材,1445.0,33.39,31.79,48248.55
11+
2024-06-12 00:00:00,688550.XSHG,瑞联新材,1445.0,34.18,31.79,49390.1
12+
2024-06-13 00:00:00,688550.XSHG,瑞联新材,1445.0,34.7,31.79,50141.5
13+
2024-06-14 00:00:00,688550.XSHG,瑞联新材,1879.0,26.0,24.1077,48854.0
14+
2024-06-17 00:00:00,688550.XSHG,瑞联新材,1879.0,25.87,24.1077,48609.73
15+
2024-06-18 00:00:00,688550.XSHG,瑞联新材,1879.0,25.55,24.1077,48008.45
16+
2024-06-19 00:00:00,688550.XSHG,瑞联新材,1879.0,25.48,24.1077,47876.92
17+
2024-06-20 00:00:00,688550.XSHG,瑞联新材,1879.0,25.58,24.1077,48064.82
18+
19+
[stock_account]
20+
DataFrame
21+
{"shape":[8,4],"dtypes":{"cash":"float64","transaction_cost":"float64","market_value":"float64","total_value":"float64"},"index_dtype":"datetime64[ns]","index_name":"date","columns":["cash","transaction_cost","market_value","total_value"]}
22+
,cash,transaction_cost,market_value,total_value
23+
2024-06-11 00:00:00,1000000.0,0.0,48248.55,1048248.55
24+
2024-06-12 00:00:00,1000000.0,0.0,49390.1,1049390.1
25+
2024-06-13 00:00:00,1000000.0,0.0,50141.5,1050141.5
26+
2024-06-14 00:00:00,1000650.25,0.0,48854.0,1049504.25
27+
2024-06-17 00:00:00,1000650.25,0.0,48609.73,1049259.98
28+
2024-06-18 00:00:00,1000650.25,0.0,48008.45,1048658.7
29+
2024-06-19 00:00:00,1000650.25,0.0,47876.92,1048527.17
30+
2024-06-20 00:00:00,1000650.25,0.0,48064.82,1048715.07
31+
32+
[portfolio]
33+
DataFrame
34+
{"shape":[8,6],"dtypes":{"cash":"float64","total_value":"float64","market_value":"float64","unit_net_value":"float64","units":"float64","static_unit_net_value":"float64"},"index_dtype":"datetime64[ns]","index_name":"date","columns":["cash","total_value","market_value","unit_net_value","units","static_unit_net_value"]}
35+
,cash,total_value,market_value,unit_net_value,units,static_unit_net_value
36+
2024-06-11 00:00:00,1000000.0,1048248.55,48248.55,1.00221,1045936.55,1.0
37+
2024-06-12 00:00:00,1000000.0,1049390.1,49390.1,1.003302,1045936.55,1.0022
38+
2024-06-13 00:00:00,1000000.0,1050141.5,50141.5,1.00402,1045936.55,1.0033
39+
2024-06-14 00:00:00,1000650.25,1049504.25,48854.0,1.003411,1045936.55,1.004
40+
2024-06-17 00:00:00,1000650.25,1049259.98,48609.73,1.003177,1045936.55,1.0034
41+
2024-06-18 00:00:00,1000650.25,1048658.7,48008.45,1.002603,1045936.55,1.0032
42+
2024-06-19 00:00:00,1000650.25,1048527.17,47876.92,1.002477,1045936.55,1.0026
43+
2024-06-20 00:00:00,1000650.25,1048715.07,48064.82,1.002656,1045936.55,1.0025
44+
45+
[summary]
46+
dict
47+
{}
48+
{
49+
"strategy_name":"strategy",
50+
"start_date":"2024-06-11",
51+
"end_date":"2024-06-20",
52+
"starting_cash":"STOCK:1000000.0",
53+
"alpha":NaN,
54+
"beta":NaN,
55+
"sharpe":4.627769423802232,
56+
"excess_sharpe":NaN,
57+
"information_ratio":NaN,
58+
"tracking_error":NaN,
59+
"sortino":7.861996788106883,
60+
"volatility":0.015298451977415738,
61+
"max_drawdown":0.0015372499801217182,
62+
"excess_max_drawdown":NaN,
63+
"excess_returns":NaN,
64+
"excess_annual_returns":NaN,
65+
"win_rate":0.5,
66+
"total_value":1048715.07,
67+
"cash":1000650.25,
68+
"total_returns":0.002656490013662971,
69+
"annualized_returns":0.08715966696778854,
70+
"unit_net_value":1.002656490013663
71+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from rqalpha.apis import get_position
2+
3+
from datetime import date
4+
5+
6+
def test_s_split(run_and_assert_result):
7+
def init(context):
8+
context.s1 = "688550.XSHG"
9+
10+
def handle_bar(context, bar_dict):
11+
position = get_position(context.s1)
12+
if context.now.date() <= date(2024, 6, 13):
13+
assert position.quantity == 1445
14+
else:
15+
assert position.quantity == 1879
16+
17+
config = {
18+
"base": {
19+
"start_date": "2024-06-10",
20+
"end_date": "2024-06-20",
21+
"frequency": "1d",
22+
"init_positions": "688550.XSHG:1445",
23+
"accounts": {
24+
"stock": 1000000,
25+
}
26+
},
27+
"extra": {
28+
"log_level": "error",
29+
}
30+
}
31+
32+
run_and_assert_result(config=config, init=init, handle_bar=handle_bar)

0 commit comments

Comments
 (0)