通达信软件前后复权计算公式
发现该项目的复权数据较为混乱。
经过数据校对,目前已经实现了与通达信的复权数据 100% 匹配。
个人认为由于复权的时间窗口是动态的,所以固定的复权因子是没有什么意义的,必须实时计算。
现在分享一下复权算法与数据核对副本。
选择了两个股票,洋河股份每年大额幅度分红派息,而运达股份含有配股和配股价的权息时间数据。
权息数据
这是通达信的权息数据格式,通过通达信软件或者 GBBQ 解码可以得到相关资料,其中的重点在于送转股、分红、配股、配股价这四个字段,流通股和股本数据对通达信来说不影响复权数据。
| 权息日 |
类别 |
送转股 |
分红 |
配股 |
配股价 |
流通股变动 |
后流通股 |
总股本变动 |
后总股本 |
| 20250707 |
除权除息 |
|
22.600 |
|
|
|
|
|
|
| 20240708 |
除权除息 |
|
22.600 |
|
|
|
|
|
|
| 20230705 |
除权除息 |
|
25.500 |
|
|
|
|
|
|
| 20220711 |
除权除息 |
|
25.400 |
|
|
|
|
|
|
| 20210712 |
除权除息 |
|
18.100 |
|
|
|
|
|
|
| 20210308 |
股本变化 |
|
|
|
|
0.0 |
1649103.8 |
-2110.0 |
1986852.0 |
| 20200615 |
除权除息 |
|
12.600 |
|
|
|
|
|
|
| 20190708 |
除权除息 |
|
8.800 |
|
|
|
|
|
|
| 20180709 |
除权除息 |
|
9.100 |
|
|
|
|
|
|
| 20170710 |
除权除息 |
|
29.700 |
|
|
|
|
|
|
| 20160704 |
除权除息 |
|
3.200 |
|
|
|
|
|
|
| 20150615 |
除权除息 |
|
7.400 |
|
|
|
|
|
|
| 20140714 |
除权除息 |
|
9.100 |
|
|
|
|
|
|
| 20131009 |
股本变化 |
|
|
|
|
18000.0 |
1649103.8 |
0.0 |
1988962.0 |
| 20130708 |
除权除息 |
|
9.600 |
|
|
|
|
|
|
| 20120611 |
除权除息 |
|
9.000 |
|
|
|
|
|
|
| 20110613 |
除权除息 |
|
7.500 |
|
|
|
|
|
|
| 20101011 |
股本变化 |
|
|
|
|
1451103.8 |
1631103.8 |
0.0 |
1988962.0 |
| 20100705 |
除权除息 |
|
5.300 |
|
|
|
|
|
|
| 20090622 |
除权除息 |
|
4.600 |
|
|
|
|
|
|
| 20080604 |
除权除息 |
|
1.800 |
|
|
|
|
|
|
| 20080109 |
股本变化 |
|
|
|
|
54000.0 |
180000.0 |
0.0 |
1988962.0 |
| 20071009 |
股本变化 |
|
|
|
|
126000.0 |
126000.0 |
180000.0 |
1988962.0 |
复权计算
已知集合向量: $ \vec{S} = { \vec{s_0}, \vec{s_1}, ..., \vec{s_n} } = { (t_0, c_0), (t_1, c_1), ..., (t_n, c_n) } $
同时根据权息数据设定权息集合: $ \vec{A} = { (\alpha_i, \beta_i, \gamma_i, \epsilon_i) \mid t_0 \leq t_{\alpha_i} \leq t_n } $
其中:
- $ \alpha $ 代表分红(如,每 10 股分红 1 元)
- $ \beta $ 代表送转股(如,每 10 股派发 2 股)
- $ \gamma $ 代表配股(如,每 10 股配发 2 股)
- $ \epsilon $ 代表配股价(如,每股配价 9 元)
注意,配股价按每股计算,其他均按每 10 股计算。
前复权计算公式
通达信使用的是累计前复权模式,遵循如下约定。
时间窗口往前递归,即:
$ t_n \rightarrow t_{n-1} \rightarrow ... \rightarrow t_{0} $
分红进行除权累加递归,满足公式:
$ D(t_i) = D(t_{i+1}) \times (1 + 0.1 \cdot \beta_{t_{i+1}}) \times (1 + 0.1 \cdot \gamma_{t_{i+1}}) + \alpha_{t_{i+1}} $
送转股满足公式:
$ B(t_i) = B(t_{i+1}) \times (1 + 0.1\beta_{t_{i+1}}) + \beta_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot B(t_i) = (1 + 0.1 \cdot B(t_{i+1})) \times (1 + 0.1 \cdot \beta_{i+1}) $
配股满足公式:
$ G(t_i) = G(t_{i+1}) \times (1 + 0.1\gamma_{t_{i+1}}) + \gamma_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot G(t_i) = (1 + 0.1 \cdot G(t_{i+1})) \times (1 + 0.1 \cdot \gamma_{i+1}) $
配股价满足公式:
$ E(t_i) = E(t_{i+1}) \times (1 + 0.1\epsilon_{t_{i+1}}) + \epsilon_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot E(t_i) = (1 + 0.1 \cdot E(t_{i+1})) \times (1 + 0.1 \cdot \epsilon_{i+1}) $
对于除权收盘价 $ c'_i $ 满足如下公式:
$ c'_i \times (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot G(t_i)) = c_i - 0.1 \cdot D(t_i) + E(t_i) \times 0.1 \cdot G(t_i) $
附带 POSTGRES 实时查询语法
WITH RECURSIVE tdays AS (
SELECT
dt.code_, dt.date_,
dt.open_, dt.high_, dt.low_, dt.close_,
dt.amount_, dt.volume_,
COALESCE(fc.val0_, 0.0) AS dividend_, -- 分红,每 10 股派现金 x 元
COALESCE(fc.val1_, 0.0) AS allotment_, -- 配股价,每股配股价 x 元
COALESCE(fc.val2_, 0.0) AS bonus_, -- 送转股,每 10 股送转股比例 x 股
COALESCE(fc.val3_, 0.0) AS rights_, -- 配股,每 10 股配股比例 x 股
ROW_NUMBER() OVER (ORDER BY dt.date_ DESC) AS rn
FROM qaas.fli_day_trade dt
LEFT JOIN qaas.fli_capital fc ON fc.exchange_ = dt.exchange_ AND fc.code_ = dt.code_ AND fc.date_ = dt.date_ AND fc.category_ = 1
WHERE dt.exchange_ = :exchange AND dt.code_ = :code AND dt.date_ <= :date ORDER BY dt.date_ DESC LIMIT :days
),
accumulated AS (
SELECT
ds.code_, ds.date_, ds.rn,
ds.open_, ds.high_, ds.low_, ds.close_,
ds.amount_, ds.volume_,
ds.dividend_, ds.dividend_ AS dividend_acc_,
ds.allotment_, ds.allotment_ AS allotment_acc_,
ds.bonus_, ds.bonus_ AS bonus_acc_,
ds.rights_, ds.rights_ AS rights_acc_
FROM tdays ds
WHERE ds.rn = 1
UNION ALL
SELECT
ds.code_, ds.date_, ds.rn,
ds.open_, ds.high_, ds.low_, ds.close_,
ds.amount_, ds.volume_,
ds.dividend_, ac.dividend_acc_ * (1 + ac.rights_ * 0.1) * (1 + ac.bonus_ * 0.1) + ac.dividend_ AS dividend_acc_,
ds.allotment_, ac.allotment_ + ac.allotment_acc_ * (1 + ac.rights_ * 0.1) * (1 + ac.bonus_ * 0.1) AS allotment_acc_,
ds.bonus_, ac.bonus_acc_ * (1 + ac.bonus_ * 0.1) + ac.bonus_ AS bonus_acc_,
ds.rights_, ac.rights_acc_ * (1 + ac.rights_ * 0.1) + ac.rights_ AS rights_acc_
FROM tdays ds
JOIN accumulated ac ON ds.rn = ac.rn + 1
),
factors AS (
SELECT
ac.code_, ac.date_,
ac.amount_, ac.volume_,
(ac.open_ - ac.dividend_acc_ * 0.1 + ac.allotment_acc_ * ac.rights_acc_ * 0.1) / ((1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1)) AS open_,
(ac.high_ - ac.dividend_acc_ * 0.1 + ac.allotment_acc_ * ac.rights_acc_ * 0.1) / ((1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1)) AS high_,
(ac.low_ - ac.dividend_acc_ * 0.1 + ac.allotment_acc_ * ac.rights_acc_ * 0.1) / ((1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1)) AS low_,
(ac.close_ - ac.dividend_acc_ * 0.1 + ac.allotment_acc_ * ac.rights_acc_ * 0.1) / ((1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1)) AS close_
FROM accumulated ac
)
SELECT
fs.code_, fs.date_,
fs.open_, fs.high_, fs.low_, fs.close_,
fs.amount_, fs.volume_
FROM factors fs
ORDER BY fs.date_ ASC;
后复权计算公式
时间窗口往后递归:
$ t_0 \rightarrow t_1 \rightarrow ... \rightarrow t_{n} $
分红进行除权累加递归,满足公式:
$ D(t_{i+1}) = D(t_i) + (1 + 0.1 \cdot B_{t_{i}}) \times (1 + 0.1 \cdot G_{t_{i}}) \times \alpha_{t_{i+1}} $
送转股满足公式:
$ 1 + 0.1 \cdot B(t_{i+1}) = (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot \beta_{t_{i+1}}) $
配股满足公式:
$ 1 + 0.1 \cdot G(t_{i+1}) = (1 + 0.1 \cdot G(t_i)) \times (1 + 0.1 \cdot \gamma_{t_{i+1}}) $
配股价满足公式:
$ E(t_{i+1}) = E(t_i) + \epsilon_{t_{i+1}} \times (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot G(t_i)) $
对于除权收盘价 $ c'_i $ 满足如下公式:
$ c'i = c_i \cdot (1 + 0.1 \cdot B(t{i+1})) \cdot (1 + 0.1 \cdot G(t_{i+1})) + 0.1 \cdot D(t_{i+1}) - E(t_{i+1}) \times 0.1 \cdot G(t_{i+1}) $
附带 POSTGRES 实时查询语法
WITH RECURSIVE tdays AS (
SELECT
dt.code_, dt.date_,
dt.open_, dt.high_, dt.low_, dt.close_,
dt.amount_, dt.volume_,
COALESCE(fc.val0_, 0.0) AS dividend_, -- 分红,每 10 股派现金 x 元
COALESCE(fc.val1_, 0.0) AS allotment_, -- 配股价,每股配股价 x 元
COALESCE(fc.val2_, 0.0) AS bonus_, -- 送转股,每 10 股送转股比例 x 股
COALESCE(fc.val3_, 0.0) AS rights_, -- 配股,每 10 股配股比例 x 股
ROW_NUMBER() OVER (ORDER BY dt.date_) AS rn
FROM qaas.fli_day_trade dt
LEFT JOIN qaas.fli_capital fc ON fc.exchange_ = dt.exchange_ AND fc.code_ = dt.code_ AND fc.date_ = dt.date_ AND fc.category_ = 1
WHERE dt.exchange_ = :exchange AND dt.code_ = :code AND dt.date_ >= :date ORDER BY dt.date_ LIMIT :days
),
accumulated AS (
SELECT
ds.code_, ds.date_, ds.rn,
ds.open_, ds.high_, ds.low_, ds.close_,
ds.amount_, ds.volume_,
ds.dividend_, ds.dividend_ AS dividend_acc_,
ds.allotment_, ds.allotment_ AS allotment_acc_,
ds.bonus_, ds.bonus_ AS bonus_acc_,
ds.rights_, ds.rights_ AS rights_acc_
FROM tdays ds
WHERE ds.rn = 1
UNION ALL
SELECT
ds.code_, ds.date_, ds.rn,
ds.open_, ds.high_, ds.low_, ds.close_,
ds.amount_, ds.volume_,
ds.dividend_, ac.dividend_acc_ + ds.dividend_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) AS dividend_acc_,
ds.allotment_, ac.allotment_acc_ + ds.allotment_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) AS allotment_acc_,
ds.bonus_, ((1 + ac.bonus_acc_ * 0.1) * (1 + ds.bonus_ * 0.1) - 1) * 10 AS bonus_acc_,
ds.rights_, ((1 + ac.rights_acc_ * 0.1) * (1 + ds.rights_ * 0.1) - 1) * 10 AS rights_acc_
FROM tdays ds
JOIN accumulated ac ON ds.rn = ac.rn + 1
),
factors AS (
SELECT
ac.code_, ac.date_,
ac.amount_, ac.volume_,
ac.open_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) + ac.dividend_acc_ * 0.1 - ac.allotment_acc_ * ac.rights_acc_ * 0.1 AS open_,
ac.high_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) + ac.dividend_acc_ * 0.1 - ac.allotment_acc_ * ac.rights_acc_ * 0.1 AS high_,
ac.low_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) + ac.dividend_acc_ * 0.1 - ac.allotment_acc_ * ac.rights_acc_ * 0.1 AS low_,
ac.close_ * (1 + ac.bonus_acc_ * 0.1) * (1 + ac.rights_acc_ * 0.1) + ac.dividend_acc_ * 0.1 - ac.allotment_acc_ * ac.rights_acc_ * 0.1 AS close_
FROM accumulated ac
)
SELECT
fs.code_, fs.date_,
fs.open_, fs.high_, fs.low_, fs.close_,
fs.amount_, fs.volume_
FROM factors fs;
002304.xlsx
300772.xlsx
通达信软件前后复权计算公式
发现该项目的复权数据较为混乱。
经过数据校对,目前已经实现了与通达信的复权数据 100% 匹配。
个人认为由于复权的时间窗口是动态的,所以固定的复权因子是没有什么意义的,必须实时计算。
现在分享一下复权算法与数据核对副本。
选择了两个股票,洋河股份每年大额幅度分红派息,而运达股份含有配股和配股价的权息时间数据。
权息数据
这是通达信的权息数据格式,通过通达信软件或者 GBBQ 解码可以得到相关资料,其中的重点在于送转股、分红、配股、配股价这四个字段,流通股和股本数据对通达信来说不影响复权数据。
复权计算
已知集合向量: $ \vec{S} = { \vec{s_0}, \vec{s_1}, ..., \vec{s_n} } = { (t_0, c_0), (t_1, c_1), ..., (t_n, c_n) } $
同时根据权息数据设定权息集合: $ \vec{A} = { (\alpha_i, \beta_i, \gamma_i, \epsilon_i) \mid t_0 \leq t_{\alpha_i} \leq t_n } $
其中:
前复权计算公式
通达信使用的是累计前复权模式,遵循如下约定。
时间窗口往前递归,即:
$ t_n \rightarrow t_{n-1} \rightarrow ... \rightarrow t_{0} $
分红进行除权累加递归,满足公式:
$ D(t_i) = D(t_{i+1}) \times (1 + 0.1 \cdot \beta_{t_{i+1}}) \times (1 + 0.1 \cdot \gamma_{t_{i+1}}) + \alpha_{t_{i+1}} $
送转股满足公式:
$ B(t_i) = B(t_{i+1}) \times (1 + 0.1\beta_{t_{i+1}}) + \beta_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot B(t_i) = (1 + 0.1 \cdot B(t_{i+1})) \times (1 + 0.1 \cdot \beta_{i+1}) $
配股满足公式:
$ G(t_i) = G(t_{i+1}) \times (1 + 0.1\gamma_{t_{i+1}}) + \gamma_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot G(t_i) = (1 + 0.1 \cdot G(t_{i+1})) \times (1 + 0.1 \cdot \gamma_{i+1}) $
配股价满足公式:
$ E(t_i) = E(t_{i+1}) \times (1 + 0.1\epsilon_{t_{i+1}}) + \epsilon_{t_{i+1}} \Rightarrow 1 + 0.1 \cdot E(t_i) = (1 + 0.1 \cdot E(t_{i+1})) \times (1 + 0.1 \cdot \epsilon_{i+1}) $
对于除权收盘价 $ c'_i $ 满足如下公式:
$ c'_i \times (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot G(t_i)) = c_i - 0.1 \cdot D(t_i) + E(t_i) \times 0.1 \cdot G(t_i) $
附带 POSTGRES 实时查询语法
后复权计算公式
时间窗口往后递归:
$ t_0 \rightarrow t_1 \rightarrow ... \rightarrow t_{n} $
分红进行除权累加递归,满足公式:
$ D(t_{i+1}) = D(t_i) + (1 + 0.1 \cdot B_{t_{i}}) \times (1 + 0.1 \cdot G_{t_{i}}) \times \alpha_{t_{i+1}} $
送转股满足公式:
$ 1 + 0.1 \cdot B(t_{i+1}) = (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot \beta_{t_{i+1}}) $
配股满足公式:
$ 1 + 0.1 \cdot G(t_{i+1}) = (1 + 0.1 \cdot G(t_i)) \times (1 + 0.1 \cdot \gamma_{t_{i+1}}) $
配股价满足公式:
$ E(t_{i+1}) = E(t_i) + \epsilon_{t_{i+1}} \times (1 + 0.1 \cdot B(t_i)) \times (1 + 0.1 \cdot G(t_i)) $
对于除权收盘价 $ c'_i $ 满足如下公式:
$ c'i = c_i \cdot (1 + 0.1 \cdot B(t{i+1})) \cdot (1 + 0.1 \cdot G(t_{i+1})) + 0.1 \cdot D(t_{i+1}) - E(t_{i+1}) \times 0.1 \cdot G(t_{i+1}) $
附带 POSTGRES 实时查询语法
002304.xlsx
300772.xlsx