Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
R
robo-dividend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenwen.tang
robo-dividend
Commits
3615cbcd
Commit
3615cbcd
authored
May 15, 2023
by
wenwen.tang
😕
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
robo for hk
parent
4c68be65
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
308 additions
and
21 deletions
+308
-21
asset_optimize.py
asset_pool/asset_optimize.py
+20
-3
datum.py
basic/datum.py
+14
-1
config-svrobo4.yml
config-svrobo4.yml
+243
-0
config-svrobo5.yml
config-svrobo5.yml
+5
-3
holder.py
portfolios/holder.py
+15
-5
solver.py
portfolios/solver.py
+3
-2
robo_executor.py
robo_executor.py
+8
-7
No files found.
asset_pool/asset_optimize.py
View file @
3615cbcd
...
...
@@ -77,10 +77,15 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize):
self
.
_navs
=
navs
self
.
_datum
=
datum
self
.
_conf
=
get_config
(
__name__
)
@
property
def
asset_include
(
self
):
return
self
.
_conf
[
'asset-include'
]
@
property
def
asset_filter
(
self
):
return
self
.
_conf
.
get
(
'asset-filter'
)
@
property
def
optimize_count
(
self
):
return
self
.
_conf
[
'optimize-count'
]
...
...
@@ -127,11 +132,23 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize):
last_one
=
rop
.
get_last_one
(
day
=
day
,
type
=
AssetPoolType
.
OPTIMIZE
)
return
json
.
loads
(
last_one
[
'asset_ids'
])
def
get_filtered_funds
(
self
):
funds
=
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
)
if
self
.
asset_filter
:
filters
=
list
(
self
.
asset_filter
.
keys
())[
0
]
funds_in
=
[]
for
fund
in
funds
:
if
fund
[
filters
]
in
self
.
asset_filter
[
filters
]:
funds_in
.
append
(
fund
)
return
funds_in
return
funds
def
get_groups
(
self
):
funds
=
pd
.
DataFrame
(
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
))
funds
=
pd
.
DataFrame
(
self
.
get_filtered_funds
(
))
result
=
[]
for
(
category
,
asset_type
),
fund_group
in
funds
.
groupby
(
by
=
[
'category'
,
'assetType'
]):
if
category
in
self
.
asset_include
:
include
=
list
(
self
.
asset_include
.
keys
())[
0
]
for
key
,
fund_group
in
funds
.
groupby
(
by
=
include
):
if
key
in
self
.
asset_include
[
include
]:
result
.
append
(
tuple
(
fund_group
[
'id'
]))
return
result
...
...
basic/datum.py
View file @
3615cbcd
...
...
@@ -8,7 +8,7 @@ from api import DatumType, Datum, PortfoliosRisk, RoboExecutor
from
basic.dao
import
robo_base_datum
as
rbd
@
component
@
component
(
bean_name
=
'datum'
)
class
DefaultDatum
(
Datum
):
def
__init__
(
self
):
...
...
@@ -79,3 +79,16 @@ class DefaultDatum(Datum):
}))
return
True
return
False
@
component
(
bean_name
=
'datum'
)
class
HkDatum
(
DefaultDatum
):
def
get_datums
(
self
,
type
:
DatumType
=
None
,
crncy
=
None
,
risk
=
None
,
datum_ids
=
None
,
ticker
=
None
,
exclude
=
True
):
datas
=
super
()
.
get_datums
(
type
,
crncy
,
None
,
datum_ids
,
ticker
,
exclude
)
# 香港基金risk与现有risk有差异,全查出来再筛选
datas
=
[
d
for
d
in
datas
if
d
.
get
(
'hk'
)]
# 进行值的覆盖操作
datas
=
[
d
.
update
(
d
[
'hk'
])
or
d
for
d
in
datas
]
# 进行筛选操作
datas
=
[
d
for
d
in
datas
if
not
risk
or
d
[
'risk'
]
==
risk
]
return
datas
config-svrobo4.yml
0 → 100644
View file @
3615cbcd
py-jftech
:
logger
:
version
:
1
formatters
:
brief
:
format
:
"
%(asctime)s
-
%(levelname)s
-
%(message)s"
simple
:
format
:
"
%(asctime)s
-
%(filename)s
-
%(levelname)s
-
%(message)s"
handlers
:
console
:
class
:
logging.StreamHandler
formatter
:
simple
level
:
DEBUG
stream
:
ext://sys.stdout
file
:
class
:
logging.handlers.TimedRotatingFileHandler
level
:
INFO
formatter
:
brief
filename
:
${LOG_FILE:logs/info.log}
interval
:
1
backupCount
:
30
encoding
:
utf8
when
:
D
# loggers:
# basic.sync:
# level: DEBUG
# handlers: [console]
# propagate: no
root
:
level
:
${LOG_LEVEL:INFO}
handlers
:
${LOG_HANDLERS:[ console ]}
database
:
host
:
${MYSQL_HOST:192.168.68.85}
port
:
${MYSQL_PORT:3306}
user
:
${MYSQL_USER:root}
password
:
${MYSQL_PWD:changeit}
dbname
:
${MYSQL_DBNAME:jftech_robo}
injectable
:
names
:
backtest
:
robo_executor.BacktestExecutor
datum
:
basic.datum.HkDatum
hold-report
:
portfolios.holder.DivHoldReportor
mpt
:
portfolios.builder.PoemPortfoliosBuilder
# email:
# server: smtphz.qiye.163.com
# user: jft-ra@thizgroup.com
# password: 5dbb#30ec6d3
mulit-process
:
max-workers
:
${MAX_PROCESS:4}
basic
:
# 基础信息模块
sync
:
start-date
:
2007-01-01
# 同步数据开始日期
datum
:
# 资料模块
change
:
date
:
${DATUM_CHANGE_DATE}
file
:
${DATUM_CHANGE_FILE}
excludes
:
# 排除的资料彭博ticker
backtest
:
[]
real
:
[]
# navs: # 净值模块
# exrate: # 汇率,如果不开启,整个这块注释掉
# - from: EUR # 需要转换的货币类型
# ticker: EURUSD BGN Curncy # 汇率值的彭博ticker
asset-pool
:
# 资产池模块
asset-optimize
:
# 资产优选模块
sortino-weight
:
# sortino计算需要的权重,下面每一条为一次计算,e.g. months: 3, weight: 0.5 表示 3个月数据使用权重0.5来计算分值
-
months
:
3
weight
:
0.5
-
months
:
6
weight
:
0.3
-
years
:
1
weight
:
0.2
asset-include
:
{
'
riskLevel'
:[
'
LOW'
,
'
HIGH'
]}
#基金按照字典key分类,并筛选出value中的值,与下面normal-ratio设置的值相对应
asset-filter
:
{
'
risk'
:[
1
,
2
,
3
,
4
,
5
]}
#基金按照字典key分类,并筛选出value中的值,仅作为筛选
optimize-count
:
3
#基金优选个数
portfolios
:
# 投组模块
holder
:
# 持仓投组相关
init-nav
:
100000
# 初始金额
min-interval-days
:
10
# 两次实际调仓最小间隔期,单位交易日
dividend-rate
:
0
#设定年化配息率
dividend-drift-rate
:
0.1
#超过基准配息率上下10%触发配息率重置
dividend-date
:
15
#配息日,每月15号
dividend-adjust-day
:
[]
#每年的首个季度调整配息
warehouse-frequency
:
3
#每隔3个月调一次仓
solver
:
# 解算器相关
tol
:
1E-10
# 误差满足条件
navs
:
# 净值要求
range
:
# 需要净值数据的区间, days: 90 表示90自然日,months: 3 表示3个自然月
days
:
90
max-nan
:
# 最大缺失净值条件
asset
:
8
# 单一资产最多缺少多少交易日数据,则踢出资产池
day
:
0.5
# 单一交易日最多缺少百分之多少净值,则删除该交易日
normal-ratio
:
#分别对应低中高风险所占比率
LOW
:
[
0.5
,
0.5
,
0.7
]
HIGH
:
[
0.5
,
0.4
,
0.2
]
riskctl-ratio
:
LOW
:
[
0.5
,
0.5
,
0.7
]
HIGH
:
[
0.5
,
0.4
,
0.2
]
matrix-rtn-days
:
20
# 计算回报率矩阵时,回报率滚动天数
asset-count
:
[
3
,
3
]
# 投组资产个数。e.g. count 或 [min, max] 分别表示 最大最小都为count 或 最小为min 最大为max,另外这里也可以类似上面给不同风险等级分别配置
mpt
:
# mpt计算相关
cvar-beta
:
0.2
# 计算Kbeta 需要用到
quantile
:
0.9
# 分位点,也可以给不同风险等级分别配置
low-weight
:
0.05
# 最低权重
# high-weight: [ 1 ] # 最高权重比例,可给一个值,也可以给多个值,当多个值时,第一个表示只有一个资产时权重,第二个表示只有两个资产时权重,以此类推,最后一个表示其他资产个数时的权重
poem
:
# poem相关
cvar-scale-factor
:
0.1
# 计算时用到的系数
reports
:
# 报告模块相关
navs
:
type
:
FUND
tickers
:
-
TEMTECI LX Equity
-
TEPLX US Equity
-
FRDPX US Equity
-
FKRCX US Equity
-
FTNRACU LX Equity
benchmark
:
# benchmark报告
ft
:
init-amount
:
100
# 初始金额
stock-rate
:
# stock型基金比例
RR3
:
0.3
RR4
:
0.5
RR5
:
0.7
fixed-range
:
# 固定区间收益率
range-dates
:
# 固定起始截止日期
-
start
:
2008-01-01
end
:
2008-10-27
-
start
:
2011-05-02
end
:
2011-10-04
-
start
:
2013-05-08
end
:
2013-06-24
-
start
:
2014-09-03
end
:
2014-12-16
-
start
:
2015-04-28
end
:
2016-01-21
-
start
:
2018-01-26
end
:
2018-10-29
-
start
:
2020-01-20
end
:
2020-03-23
relative-range
:
# 相对区间收益率
range-dates
:
# 相对时间周期
-
days
:
1
name
:
'
一天'
-
weeks
:
1
name
:
'
一周'
-
months
:
1
name
:
'
一月'
-
months
:
3
name
:
'
三月'
-
months
:
6
name
:
'
六月'
-
years
:
1
name
:
'
一年'
-
years
:
2
name
:
'
两年'
-
years
:
3
name
:
'
三年'
-
years
:
5
name
:
'
五年'
-
years
:
10
name
:
'
十年'
-
dates
:
~
name
:
'
成立以来'
exports
:
backtest
:
# 回测导出曹策略
save-path
:
${EXPORT_PATH:excels}
# 导出报告文件存放路径,如果以./或者../开头,则会以执行python文件为根目录,如果以/开头,则为系统绝对路径,否则,以项目目录为根目录
file-name
:
${EXPORT_FILENAME:real}
# 导出报告的文件名
save-config
:
${EXPORT_CONFIG:off}
# 是否保存配置文件
include-report
:
# 需要导出的报告类型列表,下面的顺序,也代表了excel中sheet的顺序
# - funds-report # 基金资料
# - navs-report # 净值报告
-
hold-report
# 持仓报告
-
signal-report
# 信号报告
-
benckmark-report
# benckmark报告
-
combo-report
# 持仓对比
-
indicators-report
# 各种特殊指标报告
-
fixed-range-report
# 固定区间收益报告
-
relative-range-report
# 相对区间收益报告
-
year-range-report
# 单年区间业绩报告
-
month-div-rate-report
# 月度配息率比较
-
year-div-rate-report
# 年度配息率比较
real-daily
:
file-name
:
svROBO5_portfolios
include-report
:
-
daily-hold-report
-
daily-signal-report
email
:
receives
:
-
wenwen.tang@thizgroup.com
copies
:
${DAILY_EMAIL_COPIES}
subject
:
default
:
"
ROBO5_TAIBEI-实盘版-每日投組推薦_{today}"
rebalance
:
"
ROBO5_TAIBEI-实盘版-每日投組推薦_{today}_今日有調倉信號!!!"
content
:
default
:
"
Dear
All:
附件是今天生成的推薦組合,請驗收,謝謝!
注>:該郵件為自動發送,如有問題請聯繫矽谷團隊
telan_qian@chifufund.com"
rebalance
:
"
Dear
All:
附件是今天生成的推薦組合以及調倉信號,請驗收,謝謝!
注>:該郵件為自動發送,如有問題請聯繫矽谷團隊
telan_qian@chifufund.com"
daily-monitor
:
file-name
:
svROBO5_monitor
include-report
:
-
name
:
relative-range-report
# 相对区间收益报告
min-date
:
~
-
name
:
contribution-report
# 贡献率报告
min-date
:
{
days
:
30
}
-
name
:
high-weight-report
# 高风险资产占比
min-date
:
{
days
:
30
}
-
name
:
asset-pool-report
# 基金池
min-date
:
{
days
:
30
}
-
name
:
combo-report
# 持仓报告
min-date
:
{
days
:
40
}
-
name
:
mpt-report
min-date
:
{
days
:
30
}
-
name
:
signal-report
min-date
:
~
-
name
:
crisis-one-report
min-date
:
{
days
:
30
}
-
name
:
crisis-two-report
min-date
:
{
days
:
30
}
-
name
:
market-right-report
min-date
:
{
days
:
30
}
-
name
:
drift-buy-report
min-date
:
{
days
:
30
}
email
:
receives
:
-
wenwen.tang@thizgroup.com
copies
:
${MONITOR_EMAIL_COPIES}
subject
:
"
SVROBO5-实盘版-每日监测_{today}"
content
:
"
Dear
All:
附件是今天生成的监测数据,請驗收,謝謝!
注>:該郵件為自動發送,如有問題請聯繫矽谷團隊
telan_qian@chifufund.com"
robo-executor
:
# 执行器相关
use
:
${ROBO_EXECUTOR:backtest}
# 执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest
sync-data
:
${SYNC_DATA:off}
# 是否开启同步资料数据
backtest
:
# 回测执行器相关
start-date
:
2012-10-16
# 回测起始日期
end-date
:
2023-03-01
# 回测截止日期
sealing-period
:
10
#调仓封闭期
start-step
:
${BACKTEST_START_STEP:1}
# 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
end-step
:
${BACKTEST_END_STEP:3}
# 回测从哪一步执行完成后结束执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
clean-up
:
true
real
:
# 实盘执行器
start-date
:
2022-09-01
# 实盘开始时间
config-svrobo5.yml
View file @
3615cbcd
...
...
@@ -30,14 +30,15 @@ py-jftech:
level
:
${LOG_LEVEL:INFO}
handlers
:
${LOG_HANDLERS:[ console ]}
database
:
host
:
${MYSQL_HOST:
::1
}
host
:
${MYSQL_HOST:
192.168.68.85
}
port
:
${MYSQL_PORT:3306}
user
:
${MYSQL_USER:root}
password
:
${MYSQL_PWD:changeit}
dbname
:
${MYSQL_DBNAME:jftech_robo}
injectable
:
name
:
name
s
:
backtest
:
robo_executor.BacktestExecutor
datum
:
basic.datum.DefaultDatum
hold-report
:
portfolios.holder.DivHoldReportor
mpt
:
portfolios.builder.PoemPortfoliosBuilder
# email:
...
...
@@ -71,7 +72,7 @@ asset-pool: # 资产池模块
weight
:
0.3
-
years
:
1
weight
:
0.2
asset-include
:
[
'
US_STOCK'
,
'
US_IG_BOND'
,
'
US_HY_BOND'
]
asset-include
:
{
'
category'
:[
'
US_STOCK'
,
'
US_IG_BOND'
,
'
US_HY_BOND'
]}
optimize-count
:
3
#基金优选个数
portfolios
:
# 投组模块
holder
:
# 持仓投组相关
...
...
@@ -81,6 +82,7 @@ portfolios: # 投组模块
dividend-drift-rate
:
0.1
#超过基准配息率上下10%触发配息率重置
dividend-date
:
15
#配息日,每月15号
dividend-adjust-day
:
[
1
,
4
,
7
,
10
]
#每年的首个季度调整配息
warehouse-frequency
:
1
#每隔1个月调一次仓
solver
:
# 解算器相关
tol
:
1E-10
# 误差满足条件
navs
:
# 净值要求
...
...
portfolios/holder.py
View file @
3615cbcd
...
...
@@ -8,7 +8,8 @@ from py_jftech import (
component
,
autowired
,
get_config
,
next_workday
,
format_date
,
is_workday
)
from
api
import
PortfoliosHolder
,
PortfoliosRisk
,
Navs
,
RoboExecutor
,
PortfoliosType
,
PortfoliosBuilder
,
RoboReportor
from
api
import
PortfoliosHolder
,
PortfoliosRisk
,
Navs
,
RoboExecutor
,
PortfoliosType
,
PortfoliosBuilder
,
RoboReportor
,
\
DatumType
,
Datum
from
portfolios.dao
import
robo_hold_portfolios
as
rhp
from
portfolios.utils
import
format_weight
...
...
@@ -19,12 +20,14 @@ logger = logging.getLogger(__name__)
class
DividendPortfoliosHolder
(
PortfoliosHolder
):
@
autowired
(
names
=
{
'executor'
:
RoboExecutor
.
use_name
()})
def
__init__
(
self
,
navs
:
Navs
=
None
,
executor
:
RoboExecutor
=
None
,
builder
:
PortfoliosBuilder
=
None
):
def
__init__
(
self
,
navs
:
Navs
=
None
,
executor
:
RoboExecutor
=
None
,
builder
:
PortfoliosBuilder
=
None
,
datum
:
Datum
=
None
):
self
.
_navs
=
navs
self
.
_executor
=
executor
self
.
_builder
=
builder
self
.
_config
=
get_config
(
__name__
)
self
.
_last_div
=
None
self
.
_datum
=
datum
def
get_portfolio_type
(
self
,
day
,
risk
:
PortfoliosRisk
)
->
PortfoliosType
:
return
PortfoliosType
.
NORMAL
...
...
@@ -78,9 +81,10 @@ class DividendPortfoliosHolder(PortfoliosHolder):
# 每年的首个季度调整配息
if
day
.
month
in
self
.
_config
.
get
(
'dividend-adjust-day'
):
asset_nav
=
last_nav
[
'asset_nav'
]
# 配息率
div_rate
=
self
.
_last_div
*
12
/
asset_nav
# 超过基准配息率上下10%触发配息率重置
if
abs
((
self
.
_config
[
'dividend-rate'
]
-
div_rate
)
/
self
.
_config
[
'dividend-rate'
])
>
\
#
年配息率减去配息率差值
超过基准配息率上下10%触发配息率重置
if
self
.
month_dividend
>
0
and
abs
((
self
.
_config
[
'dividend-rate'
]
-
div_rate
)
/
self
.
_config
[
'dividend-rate'
])
>
\
self
.
_config
[
'dividend-drift-rate'
]:
# 以本月前一天的单位净值进行配息计算
dividend
=
last_nav
[
'asset_nav'
]
*
self
.
month_dividend
...
...
@@ -99,6 +103,7 @@ class DividendPortfoliosHolder(PortfoliosHolder):
dividend_acc
=
self
.
_last_div
+
dividend_acc
asset_nav
=
fund_av
+
fund_dividend
+
dividend
nav
=
last_nav
[
'nav'
]
*
asset_nav
/
last_nav
[
'asset_nav'
]
share
=
{
x
:
fund_av
*
w
/
navs
[
x
]
for
x
,
w
in
weight
.
items
()}
else
:
fund_av
=
self
.
init_nav
fund_div_tuple
=
self
.
get_navs_and_div
(
fund_ids
=
tuple
(
weight
),
day
=
day
)
...
...
@@ -109,7 +114,12 @@ class DividendPortfoliosHolder(PortfoliosHolder):
dividend_acc
=
dividend
+
dividend_acc
nav
=
self
.
init_nav
asset_nav
=
fund_av
+
fund_dividend
+
dividend
share
=
{
x
:
fund_av
*
w
/
navs
[
x
]
for
x
,
w
in
weight
.
items
()}
funds
=
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
)
funds_subscription_rate
=
{
fund
[
'id'
]:
fund
.
get
(
'subscriptionRate'
,
0
)
for
fund
in
funds
}
share
=
{
x
:
(
1
-
funds_subscription_rate
[
x
])
*
(
fund_av
*
w
)
/
navs
[
x
]
for
x
,
w
in
weight
.
items
()}
# 初始买入扣手续费
fee
=
sum
(
funds_subscription_rate
[
x
]
*
(
fund_av
*
w
)
for
x
,
w
in
weight
.
items
())
fund_av
=
fund_av
-
fee
rhp
.
insert
({
'date'
:
day
,
'risk'
:
risk
,
...
...
portfolios/solver.py
View file @
3615cbcd
...
...
@@ -202,7 +202,7 @@ class DefaultSolver(Solver):
return
sum
(
port_r_hist
[
0
:
self
.
k_beta
])
/
self
.
k_beta
def
get_weight
(
self
):
#
todo 根据self.risk
找配置
#
根据asset-include中的对应key
找配置
return
self
.
transfer_type
[
self
.
category
][
0
]
def
create_model
(
self
):
...
...
@@ -227,7 +227,8 @@ class DefaultSolver(Solver):
def
reset_navs
(
self
,
day
):
asset_ids
=
self
.
_assets
.
get_pool
(
day
)
datum
=
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
,
datum_ids
=
asset_ids
)
asset_ids_group
=
{
k
:
[
d
[
'id'
]
for
d
in
datum
if
d
[
'category'
]
==
k
]
for
k
in
set
(
d
[
'category'
]
for
d
in
datum
)}
category
=
list
(
get_config
(
'asset-pool'
)[
'asset-optimize'
][
'asset-include'
]
.
keys
())[
0
]
asset_ids_group
=
{
k
:
[
d
[
'id'
]
for
d
in
datum
if
d
[
category
]
==
k
]
for
k
in
set
(
d
[
category
]
for
d
in
datum
)}
navs_group
=
{}
for
category
,
asset_ids
in
asset_ids_group
.
items
():
min_date
=
day
-
relativedelta
(
**
self
.
get_config
(
'navs.range'
))
...
...
robo_executor.py
View file @
3615cbcd
...
...
@@ -21,7 +21,7 @@ logger = logging.getLogger(__name__)
@
component
(
bean_name
=
'backtest'
)
class
BacktestExecutor
(
RoboExecutor
):
@
autowired
(
names
=
{
'optimize'
:
'dividend'
})
@
autowired
(
names
=
{
'optimize'
:
'dividend'
,
'datum'
:
'hk-datum'
})
def
__init__
(
self
,
datum
:
Datum
=
None
,
pool
:
AssetPool
=
None
,
syncs
:
List
[
DataSync
]
=
None
,
export
:
RoboExportor
=
None
,
builder
:
PortfoliosBuilder
=
None
,
hold
:
PortfoliosHolder
=
None
):
...
...
@@ -37,21 +37,22 @@ class BacktestExecutor(RoboExecutor):
def
get_first_business_day
(
start_date
,
end_date
):
# 生成日期范围并转换为DataFrame
dates
=
pd
.
date_range
(
start_date
,
end_date
,
freq
=
'MS'
)
dates
=
dates
.
insert
(
0
,
start_date
)
df
=
pd
.
DataFrame
({
'dates'
:
dates
})
# 提取每个月的第一个工作日
df
[
'first_business_day'
]
=
df
[
'dates'
]
.
apply
(
lambda
x
:
pd
.
date_range
(
start
=
x
,
end
=
x
+
pd
.
offsets
.
MonthEnd
(
0
),
freq
=
'B'
)[
0
]
)
# 返回第一个工作日列表
result
=
list
(
df
[
'first_business_day'
])
delta
=
workday_range
(
start_date
,
result
[
0
])
# 每隔n个月提取第一个工作日
result
=
[]
for
i
in
range
(
0
,
len
(
df
),
get_config
(
'portfolios'
)[
'holder'
][
'warehouse-frequency'
]):
result
.
append
(
df
.
iloc
[
i
][
'first_business_day'
])
delta
=
workday_range
(
result
[
0
],
result
[
1
])
period
=
get_config
(
__name__
)[
'backtest'
][
'sealing-period'
]
if
len
(
delta
)
<=
period
:
result
.
pop
(
0
)
result
.
insert
(
0
,
start_date
)
result
.
pop
(
1
)
return
result
@
property
def
start_date
(
self
):
return
pd
.
to_datetime
(
filter_weekend
(
self
.
_config
[
'start-date'
]))
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment