Skip to content

Commit

Permalink
1. Add StockEvents and recorder for it
Browse files Browse the repository at this point in the history
2. Add TopStocks to show custom factor persistence
  • Loading branch information
foolcage committed Mar 10, 2024
1 parent 49687b3 commit 1e8f3ac
Show file tree
Hide file tree
Showing 21 changed files with 581 additions and 101 deletions.
16 changes: 16 additions & 0 deletions examples/data_runner/kdata_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Index,
Index1dKdata,
StockNews,
StockEvents,
LimitUpInfo,
BlockStock,
)
Expand Down Expand Up @@ -46,6 +47,21 @@ def record_stock_news(data_provider="em"):
)


def record_stock_events(data_provider="em"):
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,
day_data=True,
domain=StockEvents,
data_provider=data_provider,
force_update=False,
sleeping_time=0.01,
)


def report_limit_up():
latest_data = LimitUpInfo.query_data(order=LimitUpInfo.timestamp.desc(), limit=1, return_type="domain")
timestamp = latest_data[0].timestamp
Expand Down
61 changes: 26 additions & 35 deletions examples/reports/report_tops.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

from apscheduler.schedulers.background import BackgroundScheduler

from examples.report_utils import report_top_entities
from examples.report_utils import report_top_entities, inform
from zvt import init_log
from zvt.api import TopType
from zvt.contract import AdjustType
from zvt.api import TopType, get_latest_kdata_date
from zvt.domain import Block, BlockCategory
from zvt.factors.top_stocks import compute_top_stocks, get_top_stocks
from zvt.informer import EmailInformer

logger = logging.getLogger(__name__)
Expand All @@ -18,46 +20,35 @@

@sched.scheduled_job("cron", hour=17, minute=0, day_of_week="mon-fri")
def report_top_stocks():

short_period = report_top_entities(
entity_type="stock",
entity_provider="em",
data_provider="em",
periods=[*range(1, 20)],
ignore_new_stock=False,
ignore_st=True,
adjust_type=None,
top_count=30,
turnover_threshold=0,
turnover_rate_threshold=0,
informer=email_informer,
title="短期最强",
compute_top_stocks()
provider = "em"
entity_type = "stock"
target_date = get_latest_kdata_date(provider=provider, entity_type=entity_type, adjust_type=AdjustType.hfq)
selected = get_top_stocks(target_date=target_date, return_type="short")

inform(
email_informer,
entity_ids=selected,
target_date=target_date,
title=f"stock 短期最强({len(selected)})",
entity_provider=provider,
entity_type=entity_type,
em_group="短期最强",
em_group_over_write=True,
em_group_over_write_tag=True,
return_type=TopType.positive,
include_limit_up=True,
)

long_period_start = short_period + 1

report_top_entities(
entity_type="stock",
entity_provider="em",
data_provider="em",
periods=[*range(long_period_start, long_period_start + 30)],
ignore_new_stock=False,
ignore_st=True,
adjust_type=None,
top_count=30,
turnover_threshold=0,
turnover_rate_threshold=0,
informer=email_informer,
title="中期最强",
selected = get_top_stocks(target_date=target_date, return_type="long")

inform(
email_informer,
entity_ids=selected,
target_date=target_date,
title=f"stock 中期最强({len(selected)})",
entity_provider=provider,
entity_type=entity_type,
em_group="中期最强",
em_group_over_write=True,
em_group_over_write_tag=False,
return_type=TopType.positive,
)

# report_top_entities(
Expand Down
61 changes: 23 additions & 38 deletions examples/reports/report_vol_up.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

from apscheduler.schedulers.background import BackgroundScheduler

from examples.report_utils import report_targets
from examples.report_utils import report_targets, inform
from zvt import init_log
from zvt.api.kdata import get_latest_kdata_date
from zvt.api.selector import get_mini_and_small_stock, get_middle_and_big_stock
from zvt.contract import AdjustType
from zvt.factors import VolumeUpMaFactor
from zvt.factors.top_stocks import get_top_stocks
from zvt.informer import EmailInformer

logger = logging.getLogger(__name__)
Expand All @@ -20,50 +21,34 @@

@sched.scheduled_job("cron", hour=17, minute=0, day_of_week="mon-fri")
def report_vol_up_stocks():
target_date = get_latest_kdata_date(entity_type="stock", adjust_type=AdjustType.hfq, provider="em")
entity_ids = get_mini_and_small_stock(timestamp=target_date, provider="em")
provider = "em"
entity_type = "stock"
target_date = get_latest_kdata_date(provider=provider, entity_type=entity_type, adjust_type=AdjustType.hfq)
selected = get_top_stocks(target_date=target_date, return_type="small_vol_up")

report_targets(
factor_cls=VolumeUpMaFactor,
entity_provider="em",
data_provider="em",
informer=email_informer,
inform(
email_informer,
entity_ids=selected,
target_date=target_date,
title=f"stock 放量突破(半)年线小市值股票({len(selected)})",
entity_provider=provider,
entity_type=entity_type,
em_group="年线股票",
title="放量突破(半)年线小市值股票",
entity_type="stock",
em_group_over_write=True,
filter_by_volume=False,
adjust_type=AdjustType.hfq,
start_timestamp="2021-01-01",
# factor args
windows=[120, 250],
over_mode="or",
up_intervals=60,
turnover_threshold=300000000,
turnover_rate_threshold=0.02,
entity_ids=entity_ids,
em_group_over_write_tag=False,
)
selected = get_top_stocks(target_date=target_date, return_type="big_vol_up")

entity_ids = get_middle_and_big_stock(timestamp=target_date)
report_targets(
factor_cls=VolumeUpMaFactor,
entity_provider="em",
data_provider="em",
informer=email_informer,
inform(
email_informer,
entity_ids=selected,
target_date=target_date,
title=f"stock 放量突破(半)年线大市值股票({len(selected)})",
entity_provider=provider,
entity_type=entity_type,
em_group="年线股票",
title="放量突破(半)年线大市值股票",
entity_type="stock",
em_group_over_write=False,
filter_by_volume=False,
adjust_type=AdjustType.hfq,
start_timestamp="2021-01-01",
# factor args
windows=[120, 250],
over_mode="or",
up_intervals=60,
turnover_threshold=300000000,
turnover_rate_threshold=0.01,
entity_ids=entity_ids,
em_group_over_write_tag=False,
)


Expand Down
21 changes: 14 additions & 7 deletions examples/tag_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
from zvt.utils import current_date, next_date, pd_is_not_null


def get_concept(code):
with open(os.path.join(os.path.dirname(__file__), "concept.json")) as f:
concept_map = json.load(f)
concepts = [item for sublist in concept_map.values() for item in sublist]
df = BlockStock.query_data(filters=[BlockStock.stock_code == code, BlockStock.name.in_(concepts)])
return df["name"].tolist()


def industry_to_tag(industry):
if industry in ["风电设备", "电池", "光伏设备", "能源金属", "电源设备"]:
return "赛道"
Expand All @@ -30,7 +38,7 @@ def industry_to_tag(industry):
return "消费电子"
if industry in ["汽车零部件", "汽车服务", "汽车整车"]:
return "汽车"
if industry in ["电机", "通用设备", "专用设备"]:
if industry in ["电机", "通用设备", "专用设备", "仪器仪表"]:
return "智能机器"
if industry in ["电网设备", "电力行业"]:
return "电力"
Expand All @@ -56,8 +64,6 @@ def industry_to_tag(industry):
return "军工"
if industry in ["专业服务"]:
return "专业服务"
if industry in ["仪器仪表"]:
return "仪器仪表"


def build_default_tags(codes, provider="em"):
Expand Down Expand Up @@ -96,7 +102,7 @@ def get_main_line_hidden_tags():
return json.load(f)


def replace_tags(old_tag="次新股"):
def replace_tags(old_tag="仪器仪表"):
with open(os.path.join(os.path.dirname(__file__), "stock_tags.json")) as f:
stock_tags = json.load(f)
for stock_tag in stock_tags:
Expand Down Expand Up @@ -169,7 +175,7 @@ def get_core_tag(codes):
if tags:
code_tag_hidden_tag_list.append((code, tags[0], None))
else:
code_tag_hidden_tag_list.append((code, tags[0], get_hidden_code(code)))
code_tag_hidden_tag_list.append((code, "未知", get_hidden_code(code)))

return code_tag_hidden_tag_list

Expand Down Expand Up @@ -277,7 +283,8 @@ def refresh_hidden_tags():
if __name__ == "__main__":
# build_stock_tags(block_name="化工原料", tag="化工", hidden_tag=None)
# merge_tags(tags_file="stock_tags.json", hidden_tags_file="化工.json", result_file="result.json", force_update=False)
# replace_tags()
check_tags()
# replace_tags(old_tag="仪器仪表")
# check_tags()
# complete_tags()
# refresh_hidden_tags()
print(get_concept(code="688787"))
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
requests==2.28.2
SQLAlchemy == 1.4.46
SQLAlchemy == 1.4.52
pandas==1.5.3
arrow==1.2.3
openpyxl==3.1.1
Expand Down
9 changes: 7 additions & 2 deletions src/zvt/api/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ def get_entity_ids_by_filter(
target_date=None,
entity_schema=Stock,
entity_ids=None,
ignore_bj=False,
):
filters = []
if not target_date:
target_date = current_date()
if ignore_new_stock:
if not target_date:
target_date = current_date()
pre_year = next_date(target_date, -365)
filters += [entity_schema.timestamp <= pre_year]
else:
filters += [entity_schema.timestamp <= target_date]
if ignore_delist:
filters += [
entity_schema.name.not_like("%退%"),
Expand All @@ -50,6 +53,8 @@ def get_entity_ids_by_filter(
entity_schema.name.not_like("%ST%"),
entity_schema.name.not_like("%*ST%"),
]
if ignore_bj:
filters += [entity_schema.exchange != "bj"]

return get_entity_ids(provider=provider, entity_schema=entity_schema, filters=filters, entity_ids=entity_ids)

Expand Down
6 changes: 6 additions & 0 deletions src/zvt/domain/misc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@

__all__ += _overall_all

# import all from submodule stock_events
from .stock_events import *
from .stock_events import __all__ as _stock_events_all

__all__ += _stock_events_all

# import all from submodule money_flow
from .money_flow import *
from .money_flow import __all__ as _money_flow_all
Expand Down
22 changes: 22 additions & 0 deletions src/zvt/domain/misc/stock_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from sqlalchemy import Column, String, DateTime
from sqlalchemy.orm import declarative_base

from zvt.contract import Mixin
from zvt.contract.register import register_schema

EventsBase = declarative_base()


class StockEvents(EventsBase, Mixin):
__tablename__ = "stock_events"
event_type = Column(String)
specific_event_type = Column(String)
notice_date = Column(DateTime)
level1_content = Column(String)
level2_content = Column(String)


register_schema(providers=["em"], db_name="stock_events", schema_base=EventsBase, entity_type="stock")
# the __all__ is generated
__all__ = ["StockEvents"]

0 comments on commit 1e8f3ac

Please sign in to comment.