[update] 选股脚本、每天下载复权因子、股票引擎更新、期货品种更新
This commit is contained in:
parent
6e4f739713
commit
58f388e67b
21
README.md
21
README.md
@ -10,6 +10,14 @@ github 链接: https://github.com/msincenselee/vnpy
|
|||||||
gitee 链接: https://gitee.com/vnpy2/vnpy
|
gitee 链接: https://gitee.com/vnpy2/vnpy
|
||||||
|
|
||||||
###Fork版本主要改进如下
|
###Fork版本主要改进如下
|
||||||
|
|
||||||
|
18、CTA股票选股引擎
|
||||||
|
|
||||||
|
-vnpy.app.stock_screener
|
||||||
|
+ 无界面选股引擎
|
||||||
|
-prod.screener_d1
|
||||||
|
+ 每日执行一次选股所有选股策略脚本
|
||||||
|
|
||||||
17、东财股票接入
|
17、东财股票接入
|
||||||
|
|
||||||
- vnpy.api.eastmoney_api,
|
- vnpy.api.eastmoney_api,
|
||||||
@ -153,10 +161,15 @@ gitee 链接: https://gitee.com/vnpy2/vnpy
|
|||||||
大佳
|
大佳
|
||||||
QQ/Wechat:28888502
|
QQ/Wechat:28888502
|
||||||
|
|
||||||
2021 股票CTA实战课程:http://www.uquant.org/course/49
|
系列在线课程
|
||||||
2021 期货缠论高级课程:http://www.uquant.org/course/48
|
|
||||||
2021 数字货币CTA课程:http://www.uquant.org/course/46
|
2021 股票CTA实战课程:http://www.uquant.org/course/49
|
||||||
2020 期货套利课程:http://www.uquant.org/course/43
|
|
||||||
|
2021 期货缠论高级课程:http://www.uquant.org/course/48
|
||||||
|
|
||||||
|
2021 数字货币CTA课程:http://www.uquant.org/course/46
|
||||||
|
|
||||||
|
2020 期货套利课程:http://www.uquant.org/course/43
|
||||||
|
|
||||||
--------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------
|
||||||
# 原版 vn.py - 基于python的开源交易平台开发框架
|
# 原版 vn.py - 基于python的开源交易平台开发框架
|
||||||
|
21
prod/jobs/daily_download_stock_adjust_factors.sh
Normal file
21
prod/jobs/daily_download_stock_adjust_factors.sh
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CONDA_HOME=~/anaconda3
|
||||||
|
#$CONDA_HOME/bin/conda deactivate
|
||||||
|
#$CONDA_HOME/bin/conda activate py37
|
||||||
|
|
||||||
|
############ Added by Huang Jianwei at 2018-04-03
|
||||||
|
# To solve the problem about Javascript runtime
|
||||||
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
############ Ended
|
||||||
|
|
||||||
|
BASE_PATH=$(cd `dirname $0`; pwd)
|
||||||
|
echo $BASE_PATH
|
||||||
|
cd `dirname $0`
|
||||||
|
PROGRAM_NAME=../../vnpy/data/stock/adjust_factor.py
|
||||||
|
|
||||||
|
# 全量下载baostock得复权因子
|
||||||
|
$CONDA_HOME/envs/py37/bin/python $PROGRAM_NAME
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ if VNPY_ROOT not in sys.path:
|
|||||||
|
|
||||||
os.environ["VNPY_TESTING"] = "1"
|
os.environ["VNPY_TESTING"] = "1"
|
||||||
from vnpy.trader.utility import load_json, save_json, append_data
|
from vnpy.trader.utility import load_json, save_json, append_data
|
||||||
from vnpy.data.stock.adjust_factor import get_adjust_factor, get_stock_base
|
from vnpy.data.stock.adjust_factor import download_adjust_factor, get_adjust_factor, get_stock_base
|
||||||
from vnpy.trader.util_wechat import send_wx_msg
|
from vnpy.trader.util_wechat import send_wx_msg
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -38,6 +38,9 @@ if __name__ == "__main__":
|
|||||||
print(u'请输入:{}目录下的子目录作为参数1'.format(os.path.abspath(os.path.join(VNPY_ROOT, 'prod'))))
|
print(u'请输入:{}目录下的子目录作为参数1'.format(os.path.abspath(os.path.join(VNPY_ROOT, 'prod'))))
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
print('下载更新所有复权因子')
|
||||||
|
download_adjust_factor()
|
||||||
|
|
||||||
# 进行报告的账号目录
|
# 进行报告的账号目录
|
||||||
account_folder = sys.argv[1]
|
account_folder = sys.argv[1]
|
||||||
account_folder = os.path.abspath(os.path.join(VNPY_ROOT, 'prod', account_folder))
|
account_folder = os.path.abspath(os.path.join(VNPY_ROOT, 'prod', account_folder))
|
||||||
|
5
prod/screener_d1/readme.md
Normal file
5
prod/screener_d1/readme.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
日线选股
|
||||||
|
|
||||||
|
配置选股策略文件 screenr_setting.json
|
||||||
|
|
||||||
|
定时任务运行 run_screener.py
|
115
prod/screener_d1/run_screener.py
Normal file
115
prod/screener_d1/run_screener.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import multiprocessing
|
||||||
|
from time import sleep
|
||||||
|
from datetime import datetime, time
|
||||||
|
from logging import DEBUG
|
||||||
|
|
||||||
|
# 将repostory的目录i,作为根目录,添加到系统环境中。
|
||||||
|
ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
if ROOT_PATH not in sys.path:
|
||||||
|
sys.path.append(ROOT_PATH)
|
||||||
|
print(f'append {ROOT_PATH} into sys.path')
|
||||||
|
|
||||||
|
from vnpy.event import EventEngine, EVENT_TIMER
|
||||||
|
from vnpy.trader.setting import SETTINGS
|
||||||
|
from vnpy.trader.engine import MainEngine
|
||||||
|
from vnpy.trader.utility import load_json
|
||||||
|
# from vnpy.gateway.gj import GjGateway
|
||||||
|
from vnpy.app.stock_screener import ScreenerApp
|
||||||
|
# from vnpy.app.cta_stock import CtaStockApp
|
||||||
|
# from vnpy.app.cta_crypto.base import EVENT_CTA_LOG
|
||||||
|
from vnpy.app.rpc_service import RpcServiceApp
|
||||||
|
# from vnpy.app.algo_broker import AlgoBrokerApp
|
||||||
|
from vnpy.app.account_recorder import AccountRecorderApp
|
||||||
|
from vnpy.trader.util_pid import update_pid
|
||||||
|
|
||||||
|
# from vnpy.trader.util_monitor import OrderMonitor, TradeMonitor, PositionMonitor, AccountMonitor, LogMonitor
|
||||||
|
|
||||||
|
SETTINGS["log.active"] = True
|
||||||
|
SETTINGS["log.level"] = DEBUG
|
||||||
|
SETTINGS["log.console"] = True
|
||||||
|
SETTINGS["log.file"] = True
|
||||||
|
|
||||||
|
screener_name = '日线选股'
|
||||||
|
|
||||||
|
import types
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
|
def excepthook(exctype: type, value: Exception, tb: types.TracebackType) -> None:
|
||||||
|
"""
|
||||||
|
Raise exception under debug mode
|
||||||
|
"""
|
||||||
|
sys.__excepthook__(exctype, value, tb)
|
||||||
|
|
||||||
|
msg = "".join(traceback.format_exception(exctype, value, tb))
|
||||||
|
|
||||||
|
print(msg, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
class DaemonService(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.event_engine = EventEngine()
|
||||||
|
self.g_count = 0
|
||||||
|
self.last_dt = datetime.now()
|
||||||
|
|
||||||
|
# 创建主引擎
|
||||||
|
self.main_engine = MainEngine(self.event_engine)
|
||||||
|
|
||||||
|
self.save_data_time = None
|
||||||
|
self.save_snapshot_time = None
|
||||||
|
|
||||||
|
# 注册定时器,用于判断重连
|
||||||
|
self.event_engine.register(EVENT_TIMER, self.on_timer)
|
||||||
|
|
||||||
|
def on_timer(self, event):
|
||||||
|
"""定时器执行逻辑,每十秒执行一次"""
|
||||||
|
|
||||||
|
# 60秒才执行一次检查
|
||||||
|
self.g_count += 1
|
||||||
|
if self.g_count <= 60:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.g_count = 0
|
||||||
|
dt = datetime.now()
|
||||||
|
|
||||||
|
# if dt.hour != self.last_dt.hour:
|
||||||
|
self.last_dt = dt
|
||||||
|
print(u'run_screener.py checkpoint:{0}'.format(dt))
|
||||||
|
self.main_engine.write_log(u'run_screener.py checkpoint:{0}'.format(dt))
|
||||||
|
if self.main_engine.get_all_completed_status():
|
||||||
|
from vnpy.trader.util_wechat import send_wx_msg
|
||||||
|
msg = f'{screener_name}完成所有选股任务'
|
||||||
|
send_wx_msg(content=msg)
|
||||||
|
self.main_engine.write_log(msg)
|
||||||
|
sleep(10)
|
||||||
|
os._exit(0)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Running in the child process.
|
||||||
|
"""
|
||||||
|
SETTINGS["log.file"] = True
|
||||||
|
|
||||||
|
# 添加选股引擎
|
||||||
|
screen_engine = self.main_engine.add_app(ScreenerApp)
|
||||||
|
screen_engine.init_engine()
|
||||||
|
|
||||||
|
self.main_engine.write_log("主引擎创建成功")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# from vnpy.trader.ui import create_qapp
|
||||||
|
# qApp = create_qapp()
|
||||||
|
# sys.excepthook = excepthook
|
||||||
|
|
||||||
|
s = DaemonService()
|
||||||
|
s.start()
|
14
prod/screener_d1/screener_setting.json
Normal file
14
prod/screener_d1/screener_setting.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"stock_screener_ThreeBuy_D1": {
|
||||||
|
"class_name": "StrategyChanlunThreeBuy",
|
||||||
|
"auto_init": true,
|
||||||
|
"auto_start": true,
|
||||||
|
"setting": {
|
||||||
|
"vt_symbols": [
|
||||||
|
"600410.SSE"
|
||||||
|
],
|
||||||
|
"all_stocks": false,
|
||||||
|
"bar_name": "D1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1274,38 +1274,47 @@ class CtaEngine(BaseEngine):
|
|||||||
"""
|
"""
|
||||||
Add a new strategy.
|
Add a new strategy.
|
||||||
"""
|
"""
|
||||||
if strategy_name in self.strategies:
|
try:
|
||||||
msg = f"创建策略失败,存在重名{strategy_name}"
|
if strategy_name in self.strategies:
|
||||||
self.write_log(msg=msg,
|
msg = f"创建策略失败,存在重名{strategy_name}"
|
||||||
level=logging.CRITICAL)
|
self.write_log(msg=msg,
|
||||||
return False, msg
|
level=logging.CRITICAL)
|
||||||
|
return False, msg
|
||||||
|
|
||||||
strategy_class = self.classes.get(class_name, None)
|
strategy_class = self.classes.get(class_name, None)
|
||||||
if not strategy_class:
|
if not strategy_class:
|
||||||
msg = f"创建策略失败,找不到策略类{class_name}"
|
msg = f"创建策略失败,找不到策略类{class_name}"
|
||||||
self.write_log(msg=msg,
|
self.write_log(msg=msg,
|
||||||
level=logging.CRITICAL)
|
level=logging.CRITICAL)
|
||||||
return False, msg
|
return False, msg
|
||||||
|
|
||||||
self.write_log(f'开始添加策略类{class_name},实例名:{strategy_name}')
|
self.write_log(f'开始添加策略类{class_name},实例名:{strategy_name}')
|
||||||
strategy = strategy_class(self, strategy_name, vt_symbols, setting)
|
strategy = strategy_class(self, strategy_name, vt_symbols, setting)
|
||||||
self.strategies[strategy_name] = strategy
|
self.strategies[strategy_name] = strategy
|
||||||
|
|
||||||
# Add vt_symbol to strategy map.
|
# Add vt_symbol to strategy map.
|
||||||
subscribe_symbol_set = self.strategy_symbol_map[strategy_name]
|
subscribe_symbol_set = self.strategy_symbol_map[strategy_name]
|
||||||
for vt_symbol in vt_symbols:
|
for vt_symbol in vt_symbols:
|
||||||
strategies = self.symbol_strategy_map[vt_symbol]
|
strategies = self.symbol_strategy_map[vt_symbol]
|
||||||
strategies.append(strategy)
|
strategies.append(strategy)
|
||||||
subscribe_symbol_set.add(vt_symbol)
|
subscribe_symbol_set.add(vt_symbol)
|
||||||
|
|
||||||
# Update to setting file.
|
# Update to setting file.
|
||||||
self.update_strategy_setting(strategy_name, setting, auto_init, auto_start)
|
self.update_strategy_setting(strategy_name, setting, auto_init, auto_start)
|
||||||
|
|
||||||
self.put_strategy_event(strategy)
|
self.put_strategy_event(strategy)
|
||||||
|
|
||||||
# 判断设置中是否由自动初始化和自动启动项目
|
# 判断设置中是否由自动初始化和自动启动项目
|
||||||
if auto_init:
|
if auto_init:
|
||||||
self.init_strategy(strategy_name, auto_start=auto_start)
|
self.init_strategy(strategy_name, auto_start=auto_start)
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
msg = f'添加策略实例{strategy_name}失败,{str(ex)}'
|
||||||
|
self.write_error(msg)
|
||||||
|
self.write_error(traceback.format_exc())
|
||||||
|
self.send_wechat(msg)
|
||||||
|
|
||||||
|
return False, f'添加策略实例{strategy_name}失败'
|
||||||
|
|
||||||
return True, f'成功添加{strategy_name}'
|
return True, f'成功添加{strategy_name}'
|
||||||
|
|
||||||
@ -1497,15 +1506,19 @@ class CtaEngine(BaseEngine):
|
|||||||
if module_name:
|
if module_name:
|
||||||
new_class_name = module_name + '.' + class_name
|
new_class_name = module_name + '.' + class_name
|
||||||
self.write_log(u'转换策略为全路径:{}'.format(new_class_name))
|
self.write_log(u'转换策略为全路径:{}'.format(new_class_name))
|
||||||
|
old_strategy_class = self.classes[class_name]
|
||||||
|
self.write_log(f'旧策略ID:{id(old_strategy_class)}')
|
||||||
strategy_class = import_module_by_str(new_class_name)
|
strategy_class = import_module_by_str(new_class_name)
|
||||||
if strategy_class is None:
|
if strategy_class is None:
|
||||||
err_msg = u'加载策略模块失败:{}'.format(class_name)
|
err_msg = u'加载策略模块失败:{}'.format(new_class_name)
|
||||||
self.write_error(err_msg)
|
self.write_error(err_msg)
|
||||||
return False, err_msg
|
return False, err_msg
|
||||||
|
|
||||||
self.write_log(f'重新加载模块成功,使用新模块:{new_class_name}')
|
self.write_log(f'重新加载模块成功,使用新模块:{new_class_name}')
|
||||||
|
self.write_log(f'新策略ID:{id(strategy_class)}')
|
||||||
self.classes[class_name] = strategy_class
|
self.classes[class_name] = strategy_class
|
||||||
|
else:
|
||||||
|
self.write_log(f'没有{class_name}的module_name,无法重新加载模块')
|
||||||
|
|
||||||
# 停止当前策略实例的运行,撤单
|
# 停止当前策略实例的运行,撤单
|
||||||
self.stop_strategy(strategy_name)
|
self.stop_strategy(strategy_name)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
""""""
|
# 股票模板
|
||||||
|
# 华富资产 @ 李来佳
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
@ -38,7 +40,7 @@ class CtaTemplate(ABC):
|
|||||||
self,
|
self,
|
||||||
cta_engine: Any,
|
cta_engine: Any,
|
||||||
strategy_name: str,
|
strategy_name: str,
|
||||||
vt_symbols: List[str],
|
vt_symbols: str,
|
||||||
setting: dict,
|
setting: dict,
|
||||||
):
|
):
|
||||||
""""""
|
""""""
|
||||||
@ -204,6 +206,9 @@ class CtaTemplate(ABC):
|
|||||||
if self.is_upper_limit(vt_symbol):
|
if self.is_upper_limit(vt_symbol):
|
||||||
self.write_error(u'涨停价不做FAK/FOK委托')
|
self.write_error(u'涨停价不做FAK/FOK委托')
|
||||||
return []
|
return []
|
||||||
|
if volume == 0:
|
||||||
|
self.write_error(f'委托数量有误,必须大于0,{vt_symbol}, price:{price}')
|
||||||
|
return []
|
||||||
return self.send_order(vt_symbol=vt_symbol,
|
return self.send_order(vt_symbol=vt_symbol,
|
||||||
direction=Direction.LONG,
|
direction=Direction.LONG,
|
||||||
offset=Offset.OPEN,
|
offset=Offset.OPEN,
|
||||||
@ -224,6 +229,9 @@ class CtaTemplate(ABC):
|
|||||||
if self.is_lower_limit(vt_symbol):
|
if self.is_lower_limit(vt_symbol):
|
||||||
self.write_error(u'跌停价不做FAK/FOK sell委托')
|
self.write_error(u'跌停价不做FAK/FOK sell委托')
|
||||||
return []
|
return []
|
||||||
|
if volume == 0:
|
||||||
|
self.write_error(f'委托数量有误,必须大于0,{vt_symbol}, price:{price}')
|
||||||
|
return []
|
||||||
return self.send_order(vt_symbol=vt_symbol,
|
return self.send_order(vt_symbol=vt_symbol,
|
||||||
direction=Direction.SHORT,
|
direction=Direction.SHORT,
|
||||||
offset=Offset.CLOSE,
|
offset=Offset.CLOSE,
|
||||||
@ -253,6 +261,7 @@ class CtaTemplate(ABC):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
if not self.trading:
|
if not self.trading:
|
||||||
|
self.write_log(f'非交易状态')
|
||||||
return []
|
return []
|
||||||
|
|
||||||
vt_orderids = self.cta_engine.send_order(
|
vt_orderids = self.cta_engine.send_order(
|
||||||
|
@ -132,7 +132,7 @@ def download_adjust_factor():
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
# 下载所有复权数据
|
# 下载所有复权数据
|
||||||
# download_adjust_factor()
|
download_adjust_factor()
|
||||||
|
|
||||||
# 下载某个股票的复权数据
|
# 下载某个股票的复权数据
|
||||||
# f = get_adjust_factor(vt_symbol='000651.SZSE',stock_name='格力电器',need_login=True)
|
# f = get_adjust_factor(vt_symbol='000651.SZSE',stock_name='格力电器',need_login=True)
|
||||||
|
@ -70,7 +70,8 @@ INIT_TDX_MARKET_MAP = {
|
|||||||
'CJL9': 28, 'CYL9': 28, 'FGL9': 28, 'JRL9': 28, 'LRL9': 28, 'MAL9': 28,
|
'CJL9': 28, 'CYL9': 28, 'FGL9': 28, 'JRL9': 28, 'LRL9': 28, 'MAL9': 28,
|
||||||
'OIL9': 28, 'PML9': 28, 'RIL9': 28, 'RML9': 28, 'RSL9': 28, 'SFL9': 28,
|
'OIL9': 28, 'PML9': 28, 'RIL9': 28, 'RML9': 28, 'RSL9': 28, 'SFL9': 28,
|
||||||
'SML9': 28, 'SRL9': 28, 'TAL9': 28, 'ICL9': 47, 'IFL9': 47, 'IHL9': 47,
|
'SML9': 28, 'SRL9': 28, 'TAL9': 28, 'ICL9': 47, 'IFL9': 47, 'IHL9': 47,
|
||||||
'TFL9': 47, 'TL9': 47, 'TSL9': 47, 'SAL9': 28, 'PGL9': 29, 'PFL9': 28, 'LH':29}
|
'TFL9': 47, 'TL9': 47, 'TSL9': 47, 'SAL9': 28, 'PGL9': 29, 'PFL9': 28,
|
||||||
|
'LHL9':29,'LUL9':30}
|
||||||
# 常量
|
# 常量
|
||||||
QSIZE = 500
|
QSIZE = 500
|
||||||
ALL_MARKET_BEGIN_HOUR = 8
|
ALL_MARKET_BEGIN_HOUR = 8
|
||||||
|
Loading…
Reference in New Issue
Block a user