hikyuu2/hikyuu/interactive/interactive.py

507 lines
15 KiB
C++
Raw Normal View History

2015-01-07 01:26:14 +08:00
#!/usr/bin/python
# -*- coding: utf8 -*-
# cp936
2017-09-26 07:07:56 +08:00
#
# The MIT License (MIT)
#
# Copyright (c) 2010-2017 fasiondog
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
2015-01-07 01:26:14 +08:00
# ===============================================================================
2017-09-26 07:07:56 +08:00
# History:
# 1. 20120926, Added by fasiondog
# ===============================================================================
2015-01-07 01:26:14 +08:00
2017-09-26 07:07:56 +08:00
import urllib
import sys
import os
import configparser
2015-01-07 01:26:14 +08:00
from hikyuu import *
from hikyuu.indicator import *
from hikyuu.trade_manage import *
from hikyuu.trade_sys.system import *
from hikyuu.trade_sys.environment import *
from hikyuu.trade_sys.condition import *
from hikyuu.trade_sys.moneymanager import *
from hikyuu.trade_sys.signal import *
from hikyuu.trade_sys.stoploss import *
from hikyuu.trade_sys.profitgoal import *
from hikyuu.trade_sys.slippage import *
from hikyuu.trade_sys.selector import *
from hikyuu.trade_sys.allocatefunds import *
2018-01-13 10:55:38 +08:00
from hikyuu.trade_sys.portfolio import *
2015-01-07 01:26:14 +08:00
2017-09-26 07:07:56 +08:00
from hikyuu.interactive import *
2015-01-07 01:26:14 +08:00
#import time
#重定向C++ stdout/stderr输出至python
2018-09-22 18:27:55 +08:00
#iodog = ostream_redirect()
iodog = OstreamRedirect()
iodog.open()
2017-09-26 07:07:56 +08:00
# ==============================================================================
2017-09-26 07:07:56 +08:00
# 引入扯线木偶
# ==============================================================================
# Puppet是一套以同花顺交易客户端为核心的完整的闭环实盘交易系统框架。
# 来自:"睿瞳深邃(https://github.com/Raytone-D" 感谢睿瞳深邃的大度共享 :-)
# 可以用tm.regBroker(crtRB(Puppet())) 的方式注册进tm实例实现实盘下单
2017-07-17 03:03:52 +08:00
if sys.platform == 'win32':
from .puppet import *
2017-06-29 14:19:02 +08:00
2017-04-09 00:50:14 +08:00
# ==============================================================================
2017-09-26 07:07:56 +08:00
#
# 读取配置信息,并初始化
#
# ==============================================================================
config_file = os.path.expanduser('~') + "/.hikyuu/hikyuu.ini"
if not os.path.exists(config_file):
# 检查老版本配置是否存在,如果存在可继续使用,否则异常终止
2018-11-29 00:11:04 +08:00
data_config_file = os.path.expanduser('~') + "/.hikyuu/data_dir.ini"
data_config = configparser.ConfigParser()
data_config.read(data_config_file)
data_dir = data_config['data_dir']['data_dir']
if sys.platform == 'win32':
config_file = data_dir + "\\hikyuu_win.ini"
else:
config_file = data_dir + "/hikyuu_linux.ini"
if not os.path.exists(config_file):
raise("未找到配置文件,请先使用数据导入工具导入数据(将自动生成配置文件)!!!")
2017-04-09 00:50:14 +08:00
2017-10-20 02:11:57 +08:00
ini = configparser.ConfigParser()
ini.read(config_file)
hku_param = Parameter()
hku_param.set("tmpdir", ini.get('hikyuu', 'tmpdir'))
if ini.has_option('hikyuu', 'logger'):
hku_param.set("logger", ini['hikyuu']['logger'])
2017-10-20 02:11:57 +08:00
base_param = Parameter()
base_info_config = ini.options('baseinfo')
for p in base_info_config:
base_param.set(p, ini.get('baseinfo', p))
2017-10-20 02:11:57 +08:00
block_param = Parameter()
block_config = ini.options('block')
for p in block_config:
block_param.set(p, ini.get('block', p))
2017-10-20 02:11:57 +08:00
preload_param = Parameter()
preload_config = ini.options('preload')
for p in preload_config:
# 注意proload参数是布尔类型
2017-10-20 02:11:57 +08:00
preload_param.set(p, ini.getboolean('preload', p))
2017-10-20 02:11:57 +08:00
kdata_param = Parameter()
kdata_config = ini.options('kdata')
for p in kdata_config:
kdata_param.set(p, ini.get('kdata', p))
2019-03-28 02:11:13 +08:00
set_log_level(LOG_LEVEL.TRACE)
2017-10-20 02:11:57 +08:00
sm = StockManager.instance()
sm.init(base_param, block_param, kdata_param, preload_param, hku_param)
2019-03-28 02:11:13 +08:00
set_log_level(LOG_LEVEL.WARN)
2015-01-07 01:26:14 +08:00
2017-09-26 07:07:56 +08:00
# ==============================================================================
2017-09-26 07:07:56 +08:00
#
# 引入blocka、blocksh、blocksz、blockg全局变量便于交互式环境下使用
#
# ==============================================================================
2017-09-26 07:07:56 +08:00
2016-04-03 00:08:31 +08:00
blocka = Block("A", "ALL")
for s in sm:
if s.type in (constant.STOCKTYPE_A, constant.STOCKTYPE_GEM):
blocka.add(s)
zsbk_a = blocka
2016-04-03 00:08:31 +08:00
blocksh = Block("A", "SH")
for s in blocka:
if s.market == "SH":
blocksh.add(s)
zsbk_sh = blocksh
2016-04-03 00:08:31 +08:00
blocksz = Block("A", "SZ")
for s in blocka:
if s.market == "SZ":
blocksz.add(s)
zsbk_sz = blocksz
2016-04-03 00:08:31 +08:00
blockg = Block("G", "创业板")
2016-04-03 00:08:31 +08:00
for s in sm:
if s.type == constant.STOCKTYPE_GEM:
2017-09-26 07:07:56 +08:00
blockg.add(s)
zsbk_cyb = blockg
blockzxb = Block("A", "中小板")
for s in blocksz:
if s.code[:3] == "002":
blockzxb.add(s)
zsbk_zxb = blockzxb
zsbk_sz50 = sm.getBlock("指数板块", "上证50")
zsbk_sz180 = sm.getBlock("指数板块", "上证180")
zsbk_hs300 = sm.getBlock("指数板块", "沪深300")
zsbk_zz100 = sm.getBlock("指数板块", "沪深300")
2019-04-11 21:25:34 +08:00
# ==============================================================================
2019-04-11 21:25:34 +08:00
#
# 设置关键类型简称
#
# ==============================================================================
O = OPEN
C = CLOSE
H = HIGH
L = LOW
A = AMO
V = VOL
2019-04-11 21:25:34 +08:00
D = Datetime
K = None
Q = Query
2019-04-11 21:25:34 +08:00
def set_global_context(stk, query):
"""设置全局的 context
:param Stock stk: Stock
:param Query query:
"""
global K, O, C, H, L, A, V
K = stk.getKData(query)
O.setContext(K)
C.setContext(K)
H.setContext(K)
L.setContext(K)
A.setContext(K)
V.setContext(K)
def get_global_context():
"""获取当前的全局上下文
:rtype: KData
"""
return C.getContext()
set_global_context(sm['sh000001'], Query(-150))
# ==============================================================================
2017-09-26 07:07:56 +08:00
#
2017-11-28 01:47:44 +08:00
# 设置默认绘图引擎
2017-09-26 07:07:56 +08:00
#
# ==============================================================================
2016-04-03 00:08:31 +08:00
2017-11-27 07:40:56 +08:00
use_draw_engine('matplotlib')
2016-04-03 00:08:31 +08:00
2017-09-26 07:07:56 +08:00
# ==============================================================================
#
# 粗略的选股函数
#
# ==============================================================================
def select(cond, start=Datetime(201801010000), end=Datetime.now(), print_out=True):
"""
#选出涨停股
C = CLOSE()
x = select(C / REF(C, 1) - 1 >= 0.0995))
:param Indicator cond:
:param Datetime start:
:param Datetime end:
:param bool print_out:
:rtype:
"""
q = QueryByDate(start, end)
d = sm.getTradingCalendar(q, 'SH')
if len(d) == 0:
return
result = []
for s in blocka:
if not s.valid:
continue
q = QueryByDate(start, end)
k = s.getKData(q)
cond.setContext(k)
2019-05-02 18:27:51 +08:00
if len(cond) > 0 and cond[-1] != constant.null_price and cond[-1] > 0 and len(k) > 0 and k[-1].datetime == d[-1]:
result.append(s)
if print_out:
print(d[-1], s)
return result
# ==============================================================================
2017-09-26 07:07:56 +08:00
#
# 增加临时的实时数据更新函数 realtimeUpdate
#
# ==============================================================================
2017-09-26 07:07:56 +08:00
2016-05-24 00:46:27 +08:00
def UpdateOneRealtimeRecord_from_sina(tmpstr):
2016-04-03 00:08:31 +08:00
try:
if len(tmpstr) > 3 and tmpstr[:3] == 'var':
a = tmpstr.split(',')
if len(a) < 9:
return
open, close, high, low = float(a[1]), float(
a[3]), float(a[4]), float(a[5])
2016-04-03 00:08:31 +08:00
transamount = float(a[9])
transcount = float(a[8])
2016-04-03 00:08:31 +08:00
d = Datetime(a[-3]+" 00")
temp = (open, high, low, close)
if 0 in temp:
return
stockstr = a[0].split('=')
stock = sm[stockstr[0][-8:]]
2016-04-03 00:08:31 +08:00
record = KRecord()
record.datetime = d
record.openPrice = open
record.highPrice = high
record.lowPrice = low
record.closePrice = close
record.transAmount = transamount
record.transCount = transcount/100
stock.realtimeUpdate(record)
2016-04-03 00:08:31 +08:00
except Exception as e:
print(tmpstr)
print(e)
2016-05-24 00:46:27 +08:00
2016-05-24 00:46:27 +08:00
def UpdateOneRealtimeRecord_from_qq(tmpstr):
try:
if len(tmpstr) > 3 and tmpstr[:2] == 'v_':
a = tmpstr.split('~')
if len(a) < 9:
return
open, close, high, low = float(a[5]), float(
a[3]), float(a[33]), float(a[34])
2016-05-24 00:46:27 +08:00
transamount = float(a[36])
transcount = float(a[37])
2016-05-24 00:46:27 +08:00
d = Datetime(int(a[30][:8] + '0000'))
temp = (open, high, low, close)
if 0 in temp:
return
stockstr = a[0].split('=')
stock = sm[stockstr[0][-8:]]
2016-05-24 00:46:27 +08:00
record = KRecord()
record.datetime = d
record.openPrice = open
record.highPrice = high
record.lowPrice = low
record.closePrice = close
record.transAmount = transamount
record.transCount = transcount/100
stock.realtimeUpdate(record)
2016-05-24 00:46:27 +08:00
except Exception as e:
print(tmpstr)
print(e)
2016-05-24 00:46:27 +08:00
def realtimePartUpdate_from_sina(queryStr):
2016-04-03 00:08:31 +08:00
result = urllib.request.urlopen(queryStr).read()
try:
result = result.decode('gbk')
except Exception as e:
print(result)
print(e)
return
2016-04-03 00:08:31 +08:00
result = result.split('\n')
for tmpstr in result:
2016-05-24 00:46:27 +08:00
UpdateOneRealtimeRecord_from_sina(tmpstr)
2016-05-24 00:46:27 +08:00
def realtimePartUpdate_from_qq(queryStr):
result = urllib.request.urlopen(queryStr).read()
try:
result = result.decode('gbk')
except Exception as e:
print(result)
print(e)
return
2016-05-24 00:46:27 +08:00
result = result.split('\n')
for tmpstr in result:
UpdateOneRealtimeRecord_from_qq(tmpstr)
2016-05-24 00:46:27 +08:00
def realtimeUpdate_from_sina_qq(source):
if source == 'sina':
queryStr = "http://hq.sinajs.cn/list="
2016-07-09 22:37:42 +08:00
update_func = realtimePartUpdate_from_sina
max_size = 140
2016-05-24 00:46:27 +08:00
elif source == 'qq':
queryStr = "http://qt.gtimg.cn/q="
2016-07-09 22:37:42 +08:00
update_func = realtimePartUpdate_from_qq
max_size = 60
2016-05-24 00:46:27 +08:00
else:
print('Not support!')
return
count = 0
2016-04-03 00:08:31 +08:00
urls = []
tmpstr = queryStr
for stock in sm:
if stock.valid and stock.type in (constant.STOCKTYPE_A,
2016-04-03 00:08:31 +08:00
constant.STOCKTYPE_INDEX,
constant.STOCKTYPE_ETF,
2016-04-03 00:08:31 +08:00
constant.STOCKTYPE_GEM):
tmpstr += ("%s,") % (stock.market_code.lower())
count = count + 1
if count >= max_size:
# urls.append(tmpstr)
2016-07-09 22:37:42 +08:00
update_func(tmpstr)
2016-04-03 00:08:31 +08:00
count = 0
tmpstr = queryStr
2016-07-09 22:37:42 +08:00
if tmpstr != queryStr:
# urls.append(tmpstr)
2016-07-09 22:37:42 +08:00
update_func(tmpstr)
# 不用并行防止过快ip被网站屏蔽
2016-07-09 22:37:42 +08:00
#from multiprocessing import Pool
#from multiprocessing.dummy import Pool as ThreadPool
#pool = ThreadPool()
# if source == 'sina':
2016-07-09 22:37:42 +08:00
# pool.map(realtimePartUpdate_from_sina, urls)
# else:
2016-07-09 22:37:42 +08:00
# pool.map(realtimePartUpdate_from_qq, urls)
# pool.close()
# pool.join()
2016-05-24 00:46:27 +08:00
def realtimeUpdate_from_tushare():
2017-05-08 02:01:44 +08:00
import tushare as ts
# 更新股票行情
2016-05-24 00:46:27 +08:00
df = ts.get_today_all()
for i in range(len(df)):
2016-07-09 22:37:42 +08:00
if df.ix[i, 'open'] == 0:
continue #
2016-05-24 00:46:27 +08:00
code = df.ix[i][0]
stock = getStock('sh' + code)
2016-05-24 00:46:27 +08:00
if stock.isNull() == True or stock.type != constant.STOCKTYPE_A:
stock = getStock('sz' + code)
if stock.isNull() == True:
continue
2016-05-24 00:46:27 +08:00
record = KRecord()
record.openPrice = df.ix[i, 'open']
record.highPrice = df.ix[i, 'high']
record.lowPrice = df.ix[i, 'low']
record.closePrice = df.ix[i, 'trade']
record.transAmount = float(df.ix[i, 'amount'])
record.transCount = float(df.ix[i, 'volume'])
2016-07-09 22:37:42 +08:00
from datetime import date
d = date.today()
record.datetime = Datetime(d)
stock.realtimeUpdate(record)
# 更新指数行情
2016-05-24 00:46:27 +08:00
df = ts.get_index()
for i in range(len(df)):
code = df.ix[i][0]
stock = getStock('sh' + code)
if stock.isNull() == True or stock.type != constant.STOCKTYPE_INDEX:
stock = getStock('sz' + code)
if stock.isNull() == True:
continue
2016-05-24 00:46:27 +08:00
total = stock.getCount(Query.DAY)
if total == 0:
continue
2016-05-24 00:46:27 +08:00
last_record = stock.getKRecord(total - 1)
2016-05-24 00:46:27 +08:00
record = KRecord()
record.openPrice = df.ix[i, 'open']
record.highPrice = df.ix[i, 'high']
record.lowPrice = df.ix[i, 'low']
record.closePrice = df.ix[i, 'close']
record.transCount = float(df.ix[i, 'volume'])
record.transAmount = float(df.ix[i, 'amount'])
if (last_record.closePrice != record.closePrice
or last_record.highPrice != record.highPrice
2016-05-24 00:46:27 +08:00
or last_record.lowPrice != record.lowPrice
or last_record.openPrice != record.openPrice):
from datetime import date
d = date.today()
record.datetime = Datetime(d)
stock.realtimeUpdate(record)
def realtimeUpdate_inner(source='tushare'):
2016-05-24 00:46:27 +08:00
if source == 'sina' or source == 'qq':
realtimeUpdate_from_sina_qq(source)
elif source == 'tushare':
realtimeUpdate_from_tushare()
else:
print(source, ' not support!')
def realtimeUpdateWrap():
pre_update_time = None
def realtimeUpdate_closure(source='tushare', delta=60):
"""
线
source: 'sina' | 'qq' | 'tushare'
delta:
"""
from datetime import timedelta, datetime
nonlocal pre_update_time
now_update_time = datetime.now()
if (pre_update_time is None) or (now_update_time - pre_update_time) > timedelta(0, delta, 0):
realtimeUpdate_inner(source)
pre_update_time = datetime.now()
print("更新完毕!", pre_update_time)
else:
print("更新间隔小于" + str(delta) + "秒,未更新")
print("上次更新时间: ", pre_update_time)
return realtimeUpdate_closure
2017-06-29 14:19:02 +08:00
realtimeUpdate = realtimeUpdateWrap()