diff --git a/README-cn.md b/README-cn.md index 431d3544..c80595ca 100644 --- a/README-cn.md +++ b/README-cn.md @@ -56,6 +56,16 @@ zvt #### 前后端分离的UI > 更灵活和可扩展,更适合于处理实时行情和用户交互,结合ZVT的动态tag系统,提供了一种量化结合主观的交易方式 + +- 初始化tag系统 + +运行以下脚本: + +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/init_tag_system.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/stock_pool_runner.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/qmt_data_runner.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/qmt_tick_runner.py + - 安装 uvicorn ```shell pip install uvicorn diff --git a/README.md b/README.md index 90df448f..5ec74ffd 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,14 @@ open [http://127.0.0.1:8050/](http://127.0.0.1:8050/) > It is more flexible and more scalable, more suitable for handling real-time market data and user interaction. > Combined with the dynamic tag system provided by ZVT, it offers a trading approach that combines AI with human intervention. +- Init tag system + +run following scripts: +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/init_tag_system.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/stock_pool_runner.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/qmt_data_runner.py +https://github.com/zvtvz/zvt/blob/master/src/zvt/tasks/qmt_tick_runner.py + - Install uvicorn ```shell pip install uvicorn diff --git a/src/zvt/factors/top_stocks.py b/src/zvt/factors/top_stocks.py index d782be48..9ff56131 100644 --- a/src/zvt/factors/top_stocks.py +++ b/src/zvt/factors/top_stocks.py @@ -151,12 +151,15 @@ def update_vol_up(): print(f"finish {target_date}") -def compute_top_stocks(provider="em"): - latest = TopStocks.query_data(limit=1, order=TopStocks.timestamp.desc(), return_type="domain") - if latest: - start = date_time_by_interval(to_time_str(latest[0].timestamp, fmt=TIME_FORMAT_DAY)) +def compute_top_stocks(provider="em", target_date=None): + if target_date: + start = target_date else: - start = "2018-01-01" + latest = TopStocks.query_data(limit=1, order=TopStocks.timestamp.desc(), return_type="domain") + if latest: + start = date_time_by_interval(to_time_str(latest[0].timestamp, fmt=TIME_FORMAT_DAY)) + else: + start = "2018-01-01" trade_days = get_trade_dates(start=start, end=today()) for target_date in trade_days: diff --git a/src/zvt/tag/tag_service.py b/src/zvt/tag/tag_service.py index e608e594..c5434562 100644 --- a/src/zvt/tag/tag_service.py +++ b/src/zvt/tag/tag_service.py @@ -105,9 +105,12 @@ def build_stock_tags( if not is_tag_info_existed(tag_info=main_tag_info, tag_type=TagType.main_tag): build_tag_info(tag_info=main_tag_info, tag_type=TagType.main_tag) - sub_tag_info = CreateTagInfoModel(tag=set_stock_tags_model.sub_tag, tag_reason=set_stock_tags_model.sub_tag_reason) - if not is_tag_info_existed(tag_info=sub_tag_info, tag_type=TagType.sub_tag): - build_tag_info(tag_info=sub_tag_info, tag_type=TagType.sub_tag) + if set_stock_tags_model.sub_tag: + sub_tag_info = CreateTagInfoModel( + tag=set_stock_tags_model.sub_tag, tag_reason=set_stock_tags_model.sub_tag_reason + ) + if not is_tag_info_existed(tag_info=sub_tag_info, tag_type=TagType.sub_tag): + build_tag_info(tag_info=sub_tag_info, tag_type=TagType.sub_tag) with contract_api.DBSession(provider="zvt", data_schema=StockTags)() as session: entity_id = set_stock_tags_model.entity_id diff --git a/src/zvt/tasks/init_tag_system.py b/src/zvt/tasks/init_tag_system.py new file mode 100644 index 00000000..f3e7388b --- /dev/null +++ b/src/zvt/tasks/init_tag_system.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from zvt.domain import Block, BlockStock, Stock +from zvt.tag.tag_service import build_default_main_tag, build_default_sub_tags +from zvt.tag.tag_utils import build_initial_stock_pool_info, build_initial_main_tag_info, build_initial_sub_tag_info + +if __name__ == "__main__": + # init tag info + build_initial_stock_pool_info() + build_initial_main_tag_info() + build_initial_sub_tag_info() + + Stock.record_data(provider="em") + Block.record_data(provider="em", sleeping_time=0) + BlockStock.record_data(provider="em", sleeping_time=0) + # init default main tag + build_default_main_tag() + + # init default sub tags + build_default_sub_tags() diff --git a/src/zvt/tasks/qmt_tick_runner.py b/src/zvt/tasks/qmt_tick_runner.py new file mode 100644 index 00000000..341f4cbc --- /dev/null +++ b/src/zvt/tasks/qmt_tick_runner.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +from zvt.broker.qmt.qmt_quote import record_tick + +if __name__ == "__main__": + from apscheduler.schedulers.background import BackgroundScheduler + + sched = BackgroundScheduler() + record_tick() + sched.add_job(func=record_tick, trigger="cron", hour=9, minute=18, day_of_week="mon-fri") + sched.start() + sched._thread.join() diff --git a/src/zvt/tasks/stock_pool_runner.py b/src/zvt/tasks/stock_pool_runner.py new file mode 100644 index 00000000..0a6fc5cb --- /dev/null +++ b/src/zvt/tasks/stock_pool_runner.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +import logging + +from apscheduler.schedulers.background import BackgroundScheduler + +from zvt import zvt_config +from zvt.api.kdata import get_latest_kdata_date +from zvt.api.selector import get_entity_ids_by_filter +from zvt.contract import AdjustType +from zvt.domain import ( + Stock, + Stock1dHfqKdata, + Stockhk, + Stockhk1dHfqKdata, + Block, + Block1dKdata, + BlockCategory, + Index, + Index1dKdata, + LimitUpInfo, +) +from zvt.factors import compute_top_stocks +from zvt.informer import EmailInformer +from zvt.informer.inform_utils import inform_email +from zvt.tag.tag_stats import build_system_stock_pools, build_stock_pool_tag_stats +from zvt.utils.recorder_utils import run_data_recorder +from zvt.utils.time_utils import current_date + +logger = logging.getLogger(__name__) + +sched = BackgroundScheduler() + +email_informer = EmailInformer() + + +def report_limit_up(): + latest_data = LimitUpInfo.query_data(order=LimitUpInfo.timestamp.desc(), limit=1, return_type="domain") + timestamp = latest_data[0].timestamp + df = LimitUpInfo.query_data(start_timestamp=timestamp, end_timestamp=timestamp, columns=["code", "name", "reason"]) + df["reason"] = df["reason"].str.split("+") + print(df) + email_informer.send_message(zvt_config["email_username"], f"{timestamp} 热门报告", f"{df}") + + +def record_stock_data(data_provider="em", entity_provider="em", sleeping_time=0): + # 涨停数据 + run_data_recorder(domain=LimitUpInfo, data_provider=None, force_update=False) + report_limit_up() + + # A股指数 + run_data_recorder(domain=Index, data_provider=data_provider, force_update=False) + # A股指数行情 + run_data_recorder( + domain=Index1dKdata, + data_provider=data_provider, + entity_provider=entity_provider, + day_data=True, + sleeping_time=sleeping_time, + ) + + # 板块(概念,行业) + run_data_recorder(domain=Block, entity_provider=entity_provider, data_provider=entity_provider, force_update=False) + # 板块行情(概念,行业) + run_data_recorder( + domain=Block1dKdata, + entity_provider=entity_provider, + data_provider=entity_provider, + day_data=True, + sleeping_time=sleeping_time, + ) + + # 报告新概念和行业 + df = Block.query_data( + filters=[Block.category == BlockCategory.concept.value], + order=Block.list_date.desc(), + index="entity_id", + limit=7, + ) + + inform_email( + entity_ids=df.index.tolist(), entity_type="block", target_date=current_date(), title="report 新概念", provider="em" + ) + + # A股标的 + run_data_recorder(domain=Stock, data_provider=data_provider, force_update=False) + # A股后复权行情 + normal_stock_ids = get_entity_ids_by_filter( + provider="em", ignore_delist=True, ignore_st=False, ignore_new_stock=False + ) + + run_data_recorder( + entity_ids=normal_stock_ids, + domain=Stock1dHfqKdata, + data_provider=data_provider, + entity_provider=entity_provider, + day_data=True, + sleeping_time=sleeping_time, + return_unfinished=True, + ) + + +def record_stockhk_data(data_provider="em", entity_provider="em", sleeping_time=2): + # 港股标的 + run_data_recorder(domain=Stockhk, data_provider=data_provider, force_update=False) + # 港股后复权行情 + df = Stockhk.query_data(filters=[Stockhk.south == True], index="entity_id") + run_data_recorder( + domain=Stockhk1dHfqKdata, + entity_ids=df.index.tolist(), + data_provider=data_provider, + entity_provider=entity_provider, + day_data=True, + sleeping_time=sleeping_time, + ) + + +def record_data_and_build_stock_pools(): + # 获取 涨停 指数 板块(概念) 个股行情数据 + record_stock_data() + + target_date = get_latest_kdata_date(provider="em", entity_type="stock", adjust_type=AdjustType.hfq) + + # 计算短期/中期最强 放量突破年线半年线个股 + compute_top_stocks(target_date=target_date) + # 放入股票池 + build_system_stock_pools() + for stock_pool_name in ["main_line", "vol_up", "大局"]: + build_stock_pool_tag_stats(stock_pool_name=stock_pool_name, target_date=target_date, force_rebuild_latest=True) + + +if __name__ == "__main__": + record_data_and_build_stock_pools() + sched.add_job(func=record_data_and_build_stock_pools, trigger="cron", hour=16, minute=00, day_of_week="mon-fri") + sched.start() + sched._thread.join() diff --git a/src/zvt/zvt_server.py b/src/zvt/zvt_server.py index 6dd4e2b6..3b288bfa 100644 --- a/src/zvt/zvt_server.py +++ b/src/zvt/zvt_server.py @@ -41,6 +41,10 @@ async def root(): add_pagination(app) -if __name__ == "__main__": +def main(): log_config = os.path.join(zvt_env["resource_path"], "log_conf.yaml") uvicorn.run("zvt_server:app", host="0.0.0.0", reload=True, port=8090, log_config=log_config) + + +if __name__ == "__main__": + main()