Merge pull request #9 from fasiondog/master

update 20230113
This commit is contained in:
pchaos 2023-01-13 11:59:05 +08:00 committed by GitHub
commit 85ba33c817
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 234 additions and 124 deletions

3
.gitignore vendored
View File

@ -13,6 +13,8 @@
*.dll
*.lib
*.so
*.so.*
*.so.*.*
*.dylib
.metadata
.settings
@ -63,6 +65,7 @@ vs2015
cover_report
cover*.info
*.gcno
vsxmake*
hikyuu/cpp/libhku_hdf5_cpp.so.200
hikyuu/cpp/libhku_hdf5_cpp.so.200.2.0
hikyuu/cpp/libhku_hdf5_hl_cpp.so.200

View File

@ -76,6 +76,13 @@ Linux下需安装依赖的开发软件包hdf-dev、mysqlclient。如 Ubuntu
.. code-block:: shell
sudo apt-get install -y libhdf5-dev libhdf5-serial-dev libmysqlclient-dev
6、转 Visual Studio 工程
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Windows 下,习惯用 msvc 调试的,可以使用 xmake project -k vsxmake -m "debug,release" 命令生成 VS 工程。命令执行后,会在当前目录下生成如 vsxmake2022 的子目录VS工程位于其内。
在 VS 内,可以将 demo 设为启动工程,进行调试。
编译与安装

View File

@ -1,6 +1,23 @@
版本发布说明
=======================
1.2.7 - 2022年11月21日
-------------------------
fixed MySQL引擎只能导入数据但实际无法使用
1.2.6 - 2022年11月18日
-------------------------
1. 新增发布 linux 下 pypi 包linux 下也可以通过 pip install hikyuu 进行安装
2. 获取股票代码表失败时增加保护
3. 增加GUI异常保护
4. fixed linux 下 mysql 数据库引擎报错(数据表名称都改为小写)
5. fixed #I5YE01 bokeh_draw.py 鼠标滑动是的时间显示问题
6. 优化系统策略延迟交易设置,将买入、卖出信号分开设置
1.2.5 - 2022年9月3日
-------------------------

View File

@ -28,8 +28,8 @@
自定义移滑价差接口:
* :py:meth:`SlippageBase.getRealBuyPrice` - 【必须】计算实际买入价格
* :py:meth:`SlippageBase.getRealSellPrice` - 【必须】计算实际卖出价格
* :py:meth:`SlippageBase.get_real_buy_price` - 【必须】计算实际买入价格
* :py:meth:`SlippageBase.get_real_sell_price` - 【必须】计算实际卖出价格
* :py:meth:`SlippageBase._calculate` - 【必须】子类计算接口
* :py:meth:`SlippageBase._clone` - 【必须】克隆接口
* :py:meth:`SlippageBase._reset` - 【可选】重载私有变量

View File

@ -145,7 +145,14 @@ def update_hdf5_extern_data(h5file, tablename, data_type):
else:
newdate = olddate // 10000 * 10000 + 1500
return newdate
def getHour2Date(olddate):
mint = olddate - olddate // 10000 * 10000
if mint <= 1130:
newdate = olddate // 10000 * 10000 + 1130
else:
newdate = olddate // 10000 * 10000 + 1500
return newdate
def getMin15Date(olddate):
mint = olddate - olddate // 10000 * 10000
if mint <= 945:
@ -219,13 +226,15 @@ def update_hdf5_extern_data(h5file, tablename, data_type):
return getMin30Date(olddate)
elif index_type == 'min60':
return getMin60Date(olddate)
elif index_type == 'hour2':
return getHour2Date(olddate)
else:
return None
if data_type == 'DAY':
index_list = ('week', 'month', 'quarter', 'halfyear', 'year')
else:
index_list = ('min15', 'min30', 'min60')
index_list = ('min15', 'min30', 'min60', 'hour2')
groupDict = {}
for index_type in index_list:

View File

@ -251,7 +251,16 @@ def update_extern_data(connect, market, code, data_type):
startdate = newdate + 1401
enddate = newdate + 1500
return (startdate, enddate)
def getHour2Date(olddate):
mint = olddate - olddate // 10000 * 10000
newdate = olddate // 10000 * 10000
if mint <= 1130:
startdate = newdate + 931
enddate = newdate + 1130
else:
startdate = newdate + 1301
enddate = newdate + 1500
return (startdate, enddate)
def getMin15Date(olddate):
mint = olddate - olddate // 10000 * 10000
newdate = olddate // 10000 * 10000
@ -351,6 +360,8 @@ def update_extern_data(connect, market, code, data_type):
return getMin30Date(olddate)
elif index_type == 'min60':
return getMin60Date(olddate)
elif index_type == 'hour2':
return getHour2Date(olddate)
else:
return None
@ -359,7 +370,7 @@ def update_extern_data(connect, market, code, data_type):
#index_list = ('week', 'month', 'quarter', 'halfyear', 'year')
base_table = get_table(connect, market, code, 'day')
else:
index_list = ('min15', 'min30', 'min60')
index_list = ('min15', 'min30', 'min60', 'hour2')
#index_list = ('min15', )
base_table = get_table(connect, market, code, 'min5')

View File

@ -27,16 +27,16 @@ from concurrent import futures
from pytdx.hq import TdxHq_API
from pytdx.config.hosts import hq_hosts
hq_hosts = [
('线1', '47.103.48.45', 7709),
('线2', '47.103.86.229', 7709),
('线3', '47.103.88.146', 7709),
('线1', '120.79.60.82', 7709),
('线2', '47.112.129.66', 7709),
('线1', '39.98.234.173', 7709),
('线2', '39.98.198.249', 7709),
('线3', '39.100.68.59', 7709),
]
# hq_hosts = [
# ('上海双线主站1', '47.103.48.45', 7709),
# ('上海双线主站2', '47.103.86.229', 7709),
# ('上海双线主站3', '47.103.88.146', 7709),
# ('深圳双线主站1', '120.79.60.82', 7709),
# ('深圳双线主站2', '47.112.129.66', 7709),
# ('北京双线主站1', '39.98.234.173', 7709),
# ('北京双线主站2', '39.98.198.249', 7709),
# ('北京双线主站3', '39.100.68.59', 7709),
# ]
def to_pytdx_market(market):

View File

@ -48,6 +48,7 @@ min5 = {min5}
min15 = {min15}
min30 = {min30}
min60 = {min60}
hour2= {hour2}
day_max = {day_max}
week_max = {week_max}
month_max = {month_max}
@ -59,7 +60,7 @@ min5_max = {min5_max}
min15_max = {min15_max}
min30_max = {min30_max}
min60_max = {min60_max}
hour2_max = {hour2_max}
[baseinfo]
type = sqlite3
@ -89,6 +90,7 @@ bj_trans = {dir}/bj_trans.h5
mysql_template = """
[hikyuu]
tmpdir = {dir}
datadir = {dir}
[block]
type = qianlong
@ -111,6 +113,7 @@ min5 = {min5}
min15 = {min15}
min30 = {min30}
min60 = {min60}
hour2 = {hour2}
day_max = {day_max}
week_max = {week_max}
month_max = {month_max}
@ -122,6 +125,7 @@ min5_max = {min5_max}
min15_max = {min15_max}
min30_max = {min30_max}
min60_max = {min60_max}
hour2_max = {hour2_max}
[baseinfo]
type = mysql

View File

@ -8,6 +8,7 @@
import requests
import json
import datetime
import time
from hikyuu.util import hku_warn, hku_info, hku_check
from .zhima import get_proxy
@ -23,11 +24,13 @@ def request_with_proxy(url):
proxy = get_proxy(new)
hku_check(proxy, "Failed get proxy!")
proxies = {'http': 'http://{}'.format(proxy)}
result = requests.get(url, proxies=proxies).text
result = requests.get(url, proxies=proxies, timeout=5).text
#hku_info("use proxy: {}".format(proxies['http']))
return result
except:
new = True
except Exception as e:
if i == 6:
new = True
time.sleep(2)
raise Exception("无法通过代理访问!")

View File

@ -205,7 +205,7 @@ def get_spot_parallel(stocklist, source='sina', use_proxy=False, batch_func=None
return batch_result
with futures.ThreadPoolExecutor() as executor:
res = executor.map(request_inner, batchs, timeout=2)
res = executor.map(request_inner, batchs, timeout=10)
result = []
for batch_result in res:

View File

@ -93,16 +93,16 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
filename = self.getUserConfigDir() + '/importdata-gui.ini'
with open(filename, 'w', encoding='utf-8') as f:
current_config.write(f)
filename = self.getHikyuuConfigFileName()
if current_config.getboolean('hdf5', 'enable', fallback=True):
data_dir = current_config['hdf5']['dir']
if not os.path.lexists(data_dir + '/tmp'):
os.mkdir(data_dir + '/tmp')
# 此处不能使用 utf-8 参数否则导致Windows下getBlock无法找到板块分类
# with open(filename, 'w', encoding='utf-8') as f:
with open(filename, 'w') as f:
f.write(
hku_config_template.hdf5_template.format(
dir=data_dir,
@ -117,6 +117,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
min15=current_config.getboolean('preload', 'min15', fallback=False),
min30=current_config.getboolean('preload', 'min30', fallback=False),
min60=current_config.getboolean('preload', 'min60', fallback=False),
hour2=current_config.getboolean('preload', 'hour2', fallback=False),
day_max=current_config.getint('preload', 'day_max', fallback=100000),
week_max=current_config.getint('preload', 'week_max', fallback=100000),
month_max=current_config.getint('preload', 'month_max', fallback=100000),
@ -128,8 +129,10 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
min15_max=current_config.getint('preload', 'min15_max', fallback=4096),
min30_max=current_config.getint('preload', 'min30_max', fallback=4096),
min60_max=current_config.getint('preload', 'min60_max', fallback=4096),
hour2_max=current_config.getint('preload', 'hour2_max', fallback=4096),
)
)
else:
data_dir = current_config['mysql']['tmpdir']
with open(filename, 'w') as f:
@ -151,6 +154,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
min15=current_config.getboolean('preload', 'min15', fallback=False),
min30=current_config.getboolean('preload', 'min30', fallback=False),
min60=current_config.getboolean('preload', 'min60', fallback=False),
hour2=current_config.getboolean('preload', 'hour2', fallback=False),
day_max=current_config.getint('preload', 'day_max', fallback=100000),
week_max=current_config.getint('preload', 'week_max', fallback=100000),
month_max=current_config.getint('preload', 'month_max', fallback=100000),
@ -162,6 +166,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
min15_max=current_config.getint('preload', 'min15_max', fallback=4096),
min30_max=current_config.getint('preload', 'min30_max', fallback=4096),
min60_max=current_config.getint('preload', 'min60_max', fallback=4096),
hour2_max=current_config.getint('preload', 'hour2_max', fallback=4096),
)
)
@ -366,6 +371,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
self.preload_min15_checkBox.setChecked(import_config.getboolean('preload', 'min15', fallback=False))
self.preload_min30_checkBox.setChecked(import_config.getboolean('preload', 'min30', fallback=False))
self.preload_min60_checkBox.setChecked(import_config.getboolean('preload', 'min60', fallback=False))
self.preload_hour2_checkBox.setChecked(import_config.getboolean('preload', 'hour2', fallback=False))
self.preload_day_spinBox.setValue(import_config.getint('preload', 'day_max', fallback=100000))
self.preload_week_spinBox.setValue(import_config.getint('preload', 'week_max', fallback=100000))
self.preload_month_spinBox.setValue(import_config.getint('preload', 'month_max', fallback=100000))
@ -377,6 +383,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
self.preload_min15_spinBox.setValue(import_config.getint('preload', 'min15_max', fallback=5120))
self.preload_min30_spinBox.setValue(import_config.getint('preload', 'min30_max', fallback=5120))
self.preload_min60_spinBox.setValue(import_config.getint('preload', 'min60_max', fallback=5120))
self.preload_hour2_spinBox.setValue(import_config.getint('preload', 'hour2_max', fallback=5120))
def getCurrentConfig(self):
import_config = ConfigParser()
@ -441,6 +448,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
'min15': self.preload_min15_checkBox.isChecked(),
'min30': self.preload_min30_checkBox.isChecked(),
'min60': self.preload_min60_checkBox.isChecked(),
'hour2': self.preload_hour2_checkBox.isChecked(),
'day_max': self.preload_day_spinBox.value(),
'week_max': self.preload_week_spinBox.value(),
'month_max': self.preload_month_spinBox.value(),
@ -452,6 +460,7 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
'min15_max': self.preload_min15_spinBox.value(),
'min30_max': self.preload_min30_spinBox.value(),
'min60_max': self.preload_min60_spinBox.value(),
'hour2_max': self.preload_hour2_spinBox.value(),
}
return import_config
@ -654,7 +663,6 @@ class MyMainWindow(QMainWindow, Ui_MainWindow):
or not os.path.isdir(config['tdx']['dir'])):
QMessageBox.about(self, "错误", "请确认通达信安装目录是否正确!")
return
try:
self.saveConfig()
except Exception as e:

View File

@ -458,6 +458,18 @@ class Ui_MainWindow(object):
self.preload_min60_spinBox.setMaximum(999999)
self.preload_min60_spinBox.setObjectName("preload_min60_spinBox")
self.gridLayout_6.addWidget(self.preload_min60_spinBox, 10, 2, 1, 1)
self.preload_hour2_checkBox = QtWidgets.QCheckBox(self.layoutWidget4)
self.preload_hour2_checkBox.setObjectName("preload_hour2_checkBox")
self.gridLayout_6.addWidget(self.preload_hour2_checkBox, 11, 0, 1, 1)
self.label_42 = QtWidgets.QLabel(self.layoutWidget4)
self.label_42.setObjectName("label_42")
self.gridLayout_6.addWidget(self.label_42, 11, 1, 1, 1)
self.preload_hour2_spinBox = QtWidgets.QSpinBox(self.layoutWidget4)
self.preload_hour2_spinBox.setMaximum(999999)
self.preload_hour2_spinBox.setObjectName("preload_hour20_spinBox")
self.gridLayout_6.addWidget(self.preload_hour2_spinBox, 11, 2, 1, 1)
self.layoutWidget5 = QtWidgets.QWidget(self.groupBox_6)
self.layoutWidget5.setGeometry(QtCore.QRect(40, 30, 362, 40))
self.layoutWidget5.setObjectName("layoutWidget5")
@ -670,6 +682,8 @@ class Ui_MainWindow(object):
self.label_33.setText(_translate("MainWindow", "最大缓存数量:"))
self.preload_min60_checkBox.setText(_translate("MainWindow", "预加载60分钟线"))
self.label_34.setText(_translate("MainWindow", "最大缓存数量:"))
self.preload_hour2_checkBox.setText(_translate("MainWindow", "预加载2小时线"))
self.label_42.setText(_translate("MainWindow", "最大缓存数量:"))
self.label_35.setText(_translate("MainWindow", "此处为 Hikyuu 运行时的数据预加载设置,请根据机器内存大小选择"))
self.label_36.setText(_translate("MainWindow", "目前加载全部日线数据目前需要约需900M内存"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_6), _translate("MainWindow", "预加载设置"))

View File

@ -155,8 +155,8 @@ def next_delta(start_time, interval, phase1_delta, phase2_delta, ignore_weekend)
elif maybe_time in (phase1_start, phase1_end, phase2_start, phase2_end):
# 如果下一次时间刚好等于时间周期的起止点,则直接返回预计的时间间隔
delta = interval_delta
elif start_time < phase1_start and phase1_start < maybe_time < phase1_end:
# 如果本次的时间小于周期1的起始时间且预计下一次的时间在phase1内则取phase1起始时间计算
elif start_time < phase1_start:
# 如果本次的时间小于周期1的起始时间则取phase1起始时间计算
delta = phase1_start - start_time
elif phase1_end < maybe_time < phase2_start:
delta = phase2_start - start_time
@ -271,7 +271,11 @@ def collect(use_proxy, source, seconds, phase1, phase2, ignore_weekend):
#pub_sock.send('{}{}'.format(spot_topic, '[end spot]').encode('utf-8'))
end_send_spot()
delta = next_delta(start_time, seconds, phase1_delta, phase2_delta, ignore_weekend)
time.sleep(delta.total_seconds())
hku_info("sleep {}'s".format(delta.total_seconds()))
if delta.total_seconds() > 0:
time.sleep(delta.total_seconds())
else:
pass
except KeyboardInterrupt:
print("Ctrl-C 终止")
break

View File

@ -111,7 +111,7 @@ for p in block_config:
preload_param = Parameter()
preload_config = ini.options('preload')
for p in preload_config:
if p in ('day', 'week', 'month', 'quarter', 'halfyear', 'year', 'min', 'min5', 'min15', 'min30', 'min60'):
if p in ('day', 'week', 'month', 'quarter', 'halfyear', 'year', 'min', 'min5', 'min15', 'min30', 'min60', 'hour2'):
preload_param[p] = ini.getboolean('preload', p)
else:
preload_param[p] = ini.getint('preload', p)

View File

@ -5,9 +5,7 @@
* Author: fasiondog
*/
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <functional>
#include "StockManager.h"
#include "KDataImp.h"
@ -98,10 +96,10 @@ size_t KDataImp::getPos(const Datetime& datetime) {
KRecordList::const_iterator iter;
KRecord comp_record;
comp_record.datetime = datetime;
boost::function<bool(const KRecord&, const KRecord&)> f =
boost::bind(&KRecord::datetime, _1) < boost::bind(&KRecord::datetime, _2);
iter = lower_bound(m_buffer.begin(), m_buffer.end(), comp_record, f);
iter = lower_bound(
m_buffer.begin(), m_buffer.end(), comp_record,
std::bind(std::less<Datetime>(), std::bind(&KRecord::datetime, std::placeholders::_1),
std::bind(&KRecord::datetime, std::placeholders::_2)));
if (iter == m_buffer.end() || iter->datetime != datetime) {
return Null<size_t>();
}
@ -180,7 +178,6 @@ void KDataImp::_recoverForward() {
Datetime end_date(m_buffer.back().datetime.date() + bd::days(1));
StockWeightList weightList = m_stock.getWeight(start_date, end_date);
StockWeightList::const_iterator weightIter = weightList.begin();
StockWeightList::const_iterator pre_weightIter = weightIter;
size_t pre_pos = 0;
for (; weightIter != weightList.end(); ++weightIter) {

View File

@ -299,6 +299,10 @@ void Stock::loadKDataToBuffer(KQuery::KType inkType) {
int start = total <= max_num ? 0 : total - max_num;
{
std::unique_lock<std::shared_mutex> lock(*(m_data->pMutex[kType]));
// 需要对是否已缓存进行二次判定,防止加锁之前已被缓存
if (m_data->pKData.find(kType) != m_data->pKData.end() && m_data->pKData[kType]) {
return;
}
KRecordList* ptr_klist = new KRecordList;
m_data->pKData[kType] = ptr_klist;
(*ptr_klist) = driver->getKRecordList(m_data->m_market, m_data->m_code,
@ -585,7 +589,8 @@ KRecordList Stock::_getKRecordListFromBuffer(size_t start_ix, size_t end_ix,
end_ix, total);
size_t length = end_ix > total ? total - start_ix : end_ix - start_ix;
result.resize(length);
std::memcpy(&(result.front()), &((*m_data->pKData[ktype])[start_ix]), sizeof(KRecord) * length);
std::memcpy((void*)&(result.front()), &((*m_data->pKData[ktype])[start_ix]),
sizeof(KRecord) * length);
return result;
}
@ -714,6 +719,11 @@ void Stock::realtimeUpdate(KRecord record, KQuery::KType inktype) {
// 加写锁
std::unique_lock<std::shared_mutex> lock(*(m_data->pMutex[ktype]));
// 需要对是否已缓存进行二次判定,防止加锁之前缓存被释放
if (m_data->pKData.find(ktype) == m_data->pKData.end() || !m_data->pKData[ktype]) {
return;
}
if (m_data->pKData[ktype]->empty()) {
m_data->pKData[ktype]->push_back(record);
return;

View File

@ -75,6 +75,7 @@ Parameter default_preload_param() {
param.set<bool>("min15", false);
param.set<bool>("min30", false);
param.set<bool>("min60", false);
param.set<bool>("hour2", false);
param.set<bool>("ticks", false);
param.set<int>("day_max", 100000);
param.set<int>("week_max", 100000);
@ -87,6 +88,7 @@ Parameter default_preload_param() {
param.set<int>("min15_max", 5120);
param.set<int>("min30_max", 5120);
param.set<int>("min60_max", 5120);
param.set<int>("hour2_max", 5120);
param.set<int>("ticks_max", 5120);
return param;
}
@ -191,6 +193,9 @@ void StockManager::setKDataDriver(const KDataDriverConnectPoolPtr& driver) {
bool preload_min60 = m_preloadParam.tryGet<bool>("min60", false);
HKU_INFO_IF(preload_min60, "Preloading all 60 min kdata to buffer!");
bool preload_hour2 = m_preloadParam.tryGet<bool>("hour2", false);
HKU_INFO_IF(preload_hour2, "Preloading all 120 min kdata to buffer!");
if (!driver->getPrototype()->canParallelLoad()) {
for (auto iter = m_stockDict.begin(); iter != m_stockDict.end(); ++iter) {
if (iter->second.market() == "TMP")
@ -218,6 +223,8 @@ void StockManager::setKDataDriver(const KDataDriverConnectPoolPtr& driver) {
iter->second.loadKDataToBuffer(KQuery::MIN30);
if (preload_min60)
iter->second.loadKDataToBuffer(KQuery::MIN60);
if (preload_hour2)
iter->second.loadKDataToBuffer(KQuery::HOUR2);
}
} else {
@ -249,6 +256,8 @@ void StockManager::setKDataDriver(const KDataDriverConnectPoolPtr& driver) {
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN30); });
if (preload_min60)
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN60); });
if (preload_hour2)
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::HOUR2); });
}
}

View File

@ -33,7 +33,7 @@ struct StockInfo {
static const char* getSelectSQL() {
return "select c.market, a.code, a.name, a.type, a.valid, a.startDate, a.endDate, b.tick, "
"b.tickValue, b.precision, b.minTradeNumber, b.maxTradeNumber from stock a, "
"StockTypeInfo b, market c where a.type = b.id and a.marketid = c.marketid";
"stocktypeinfo b, market c where a.type = b.id and a.marketid = c.marketid";
}
void load(const SQLStatementPtr& st) {

View File

@ -14,7 +14,7 @@
namespace hku {
class HolidayTable {
TABLE_BIND1(Holiday, date)
TABLE_BIND1(holiday, date)
public:
HolidayTable() : date(Datetime().number()) {}

View File

@ -77,21 +77,21 @@ private:
public:
static const char* getInsertSQL() {
return "insert into `Market` "
return "insert into `market` "
"(`marketid`, `market`, `name`, `description`, `code`, `lastDate`,"
" `openTime1`, `closeTime1`, `openTime2`, `closeTime2`) "
"values (?,?,?,?,?,?,?,?,?,?)";
}
static const char* getUpdateSQL() {
return "update `Market` set `market`=?, `name`=?, `description`=?, "
return "update `market` set `market`=?, `name`=?, `description`=?, "
"`code`=?, `lastDate`=?, `openTime1`=?, `closeTime1`=?, "
"`openTime2=`=?, `closeTime2`=? where `marketid`=?";
}
static const char* getSelectSQL() {
return "select `marketid`,`market`,`name`, `description`, `code`, `lastDate`, "
"`openTime1`, `closeTime1`, `openTime2`, `closeTime2` from `Market`";
"`openTime1`, `closeTime1`, `openTime2`, `closeTime2` from `market`";
}
void save(const SQLStatementPtr& st) const {

View File

@ -16,7 +16,7 @@
namespace hku {
class StockWeightTable {
TABLE_BIND9(stkWeight, stockid, date, countAsGift, countForSell, priceForSell, bonus,
TABLE_BIND9(stkweight, stockid, date, countAsGift, countForSell, priceForSell, bonus,
countOfIncreasement, totalCount, freeCount)
public:

View File

@ -125,6 +125,7 @@ bool H5KDataDriver::_init() {
m_h5file_map[market + "_MIN15"] = h5file;
m_h5file_map[market + "_MIN30"] = h5file;
m_h5file_map[market + "_MIN60"] = h5file;
m_h5file_map[market + "_HOUR2"] = h5file;
} else if (ktype == "TIME") {
filename = getParam<string>(*iter);
@ -233,6 +234,9 @@ bool H5KDataDriver::_getH5FileAndGroup(const string& market, const string& code,
} else if (kType == KQuery::MIN60) {
CHECK_GROUP_EXISTS_RET(out_file, "min60", false);
out_group = out_file->openGroup("min60");
} else if (kType == KQuery::HOUR2) {
CHECK_GROUP_EXISTS_RET(out_file, "hour2", false);
out_group = out_file->openGroup("hour2");
} else if (kType == KQuery::DAY) {
CHECK_GROUP_EXISTS_RET(out_file, "data", false);
out_group = out_file->openGroup("data");
@ -431,7 +435,7 @@ bool H5KDataDriver::_getOtherIndexRangeByDate(const string& market, const string
assert(KQuery::WEEK == query.kType() || KQuery::MONTH == query.kType() ||
KQuery::QUARTER == query.kType() || KQuery::HALFYEAR == query.kType() ||
KQuery::YEAR == query.kType() || KQuery::MIN15 == query.kType() ||
KQuery::MIN30 == query.kType() || KQuery::MIN60 == query.kType());
KQuery::MIN30 == query.kType() || KQuery::MIN60 == query.kType() || KQuery::HOUR2 == query.kType());
out_start = 0;
out_end = 0;
HKU_IF_RETURN(query.startDatetime() >= query.endDatetime(), false);

View File

@ -386,7 +386,7 @@ string TdxKDataDriver::_getFileName(const string& market, const string& code, KQ
if (ktype == KQuery::MIN) {
filename = m_dirname + "\\" + market + "\\minline\\" + market + code + ".lc1";
} else if (ktype == KQuery::MIN5 || ktype == KQuery::MIN15 || ktype == KQuery::MIN30 ||
ktype == KQuery::MIN60) {
ktype == KQuery::MIN60 || ktype == KQuery::HOUR2) {
filename = m_dirname + "\\" + market + "\\fzline\\" + market + code + ".lc5";
} else if (ktype == KQuery::DAY || ktype == KQuery::WEEK || ktype == KQuery::MONTH ||
ktype == KQuery::QUARTER || ktype == KQuery::HALFYEAR || ktype == KQuery::YEAR) {

View File

@ -69,7 +69,7 @@ Datetime::Datetime(unsigned long long datetime) {
m_data = bt::ptime(d, bt::time_duration((unsigned short)hh, (unsigned short)mm, 0));
} else {
HKU_THROW_EXCEPTION(std::out_of_range,
"Only suport YYYYMMDDhhmm or YYYYMMDD, but current param is {}",
"Only support YYYYMMDDhhmm or YYYYMMDD, but current param is {}",
datetime);
}
}

View File

@ -211,7 +211,6 @@ void HKU_API startSpotAgent(bool print) {
if (preloadParam.tryGet<bool>("min60", false)) {
agent.addProcess(std::bind(updateStockMinData, std::placeholders::_1, KQuery::MIN60));
}
if (preloadParam.tryGet<bool>("min3", false)) {
agent.addProcess(std::bind(updateStockMinData, std::placeholders::_1, KQuery::MIN3));
}

View File

@ -55,6 +55,7 @@ void StrategyBase::_initDefaultParam() {
setParam<bool>("enable_15min_clock", false);
setParam<bool>("enable_30min_clock", false);
setParam<bool>("enable_60min_clock", false);
setParam<bool>("enable_2hour_clock", false);
}
void StrategyBase::run() {
@ -246,6 +247,7 @@ void StrategyBase::_addTimer() {
_addClockEvent("enable_15min_clock", Minutes(15), openTime, closeTime);
_addClockEvent("enable_30min_clock", Minutes(30), openTime, closeTime);
_addClockEvent("enable_60min_clock", Minutes(60), openTime, closeTime);
_addClockEvent("enable_2hour_clock", Hours(2), openTime, closeTime);
}
void StrategyBase::_addClockEvent(const string& enable, TimeDelta delta, TimeDelta openTime,

View File

@ -7,7 +7,7 @@
#include <fstream>
#include <sstream>
#include <boost/bind.hpp>
#include <functional>
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include "TradeManager.h"
@ -316,16 +316,16 @@ TradeRecordList TradeManager::getTradeList(const Datetime& start_date,
TradeRecord temp_record;
temp_record.datetime = start_date;
auto low =
lower_bound(m_trade_list.begin(), m_trade_list.end(), temp_record,
boost::bind(std::less<Datetime>(), boost::bind(&TradeRecord::datetime, _1),
boost::bind(&TradeRecord::datetime, _2)));
auto low = lower_bound(
m_trade_list.begin(), m_trade_list.end(), temp_record,
std::bind(std::less<Datetime>(), std::bind(&TradeRecord::datetime, std::placeholders::_1),
std::bind(&TradeRecord::datetime, std::placeholders::_2)));
temp_record.datetime = end_date;
auto high =
lower_bound(m_trade_list.begin(), m_trade_list.end(), temp_record,
boost::bind(std::less<Datetime>(), boost::bind(&TradeRecord::datetime, _1),
boost::bind(&TradeRecord::datetime, _2)));
auto high = lower_bound(
m_trade_list.begin(), m_trade_list.end(), temp_record,
std::bind(std::less<Datetime>(), std::bind(&TradeRecord::datetime, std::placeholders::_1),
std::bind(&TradeRecord::datetime, std::placeholders::_2)));
result.insert(result.end(), low, high);
@ -863,11 +863,13 @@ TradeRecord TradeManager::buy(const Datetime& datetime, const Stock& stock, pric
if (result.datetime > m_broker_last_datetime) {
list<OrderBrokerPtr>::const_iterator broker_iter = m_broker_list.begin();
Datetime realtime, nulltime;
for (; broker_iter != m_broker_list.end(); ++broker_iter) {
Datetime realtime =
realtime =
(*broker_iter)->buy(datetime, stock.market(), stock.code(), realPrice, number);
if (realtime != Null<Datetime>())
if (realtime != nulltime && realtime > m_broker_last_datetime) {
m_broker_last_datetime = realtime;
}
}
}
@ -951,10 +953,13 @@ TradeRecord TradeManager::sell(const Datetime& datetime, const Stock& stock, pri
if (result.datetime > m_broker_last_datetime) {
list<OrderBrokerPtr>::const_iterator broker_iter = m_broker_list.begin();
Datetime realtime, nulltime;
for (; broker_iter != m_broker_list.end(); ++broker_iter) {
Datetime realtime =
realtime =
(*broker_iter)->sell(datetime, stock.market(), stock.code(), realPrice, real_number);
m_broker_last_datetime = realtime;
if (realtime != nulltime && realtime > m_broker_last_datetime) {
m_broker_last_datetime = realtime;
}
}
}
@ -1527,9 +1532,10 @@ void TradeManager::updateWithWeight(const Datetime& datetime) {
} /* for weight */
} /* for position */
std::sort(new_trade_buffer.begin(), new_trade_buffer.end(),
boost::bind(std::less<Datetime>(), boost::bind(&TradeRecord::datetime, _1),
boost::bind(&TradeRecord::datetime, _2)));
std::sort(
new_trade_buffer.begin(), new_trade_buffer.end(),
std::bind(std::less<Datetime>(), std::bind(&TradeRecord::datetime, std::placeholders::_1),
std::bind(&TradeRecord::datetime, std::placeholders::_2)));
size_t total = new_trade_buffer.size();
for (size_t i = 0; i < total; ++i) {

View File

@ -5,7 +5,6 @@
* Author: fasiondog
*/
#include <boost/bind.hpp>
#include "../../trade_manage/crt/crtTM.h"
#include "Portfolio.h"

View File

@ -32,7 +32,7 @@ public:
* @param work_num 线线
*/
TimerManager(size_t work_num = 1)
: m_current_timer_id(-1), m_stop(true), m_work_num(work_num) {}
: m_stop(true), m_current_timer_id(-1), m_work_num(work_num) {}
/** 析构函数 */
~TimerManager() {

View File

@ -41,14 +41,15 @@ public:
: m_done(false), m_worker_num(n), m_runnging_util_empty(util_empty) {
try {
// 先初始化相关资源,再启动线程
for (int i = 0; i < m_worker_num; i++) {
for (size_t i = 0; i < m_worker_num; i++) {
// 创建工作线程及其任务队列
m_threads_status.push_back(nullptr);
m_queues.push_back(
std::unique_ptr<MQStealQueue<task_type>>(new MQStealQueue<task_type>));
}
for (int i = 0; i < m_worker_num; i++) {
m_threads.push_back(std::thread(&MQStealThreadPool::worker_thread, this, i));
for (size_t i = 0; i < m_worker_num; i++) {
m_threads.push_back(
std::thread(&MQStealThreadPool::worker_thread, this, static_cast<int>(i)));
}
} catch (...) {
m_done = true;

View File

@ -41,14 +41,15 @@ public:
: m_done(false), m_worker_num(n), m_runnging_util_empty(util_empty) {
try {
// 先初始化相关资源,再启动线程
for (int i = 0; i < m_worker_num; i++) {
for (size_t i = 0; i < m_worker_num; i++) {
// 创建工作线程及其任务队列
m_threads_status.push_back(nullptr);
m_queues.push_back(
std::unique_ptr<ThreadSafeQueue<task_type>>(new ThreadSafeQueue<task_type>));
}
for (int i = 0; i < m_worker_num; i++) {
m_threads.push_back(std::thread(&MQThreadPool::worker_thread, this, i));
for (size_t i = 0; i < m_worker_num; i++) {
m_threads.push_back(
std::thread(&MQThreadPool::worker_thread, this, static_cast<int>(i)));
}
} catch (...) {
m_done = true;

View File

@ -43,13 +43,14 @@ public:
: m_done(false), m_runnging_util_empty(util_empty), m_worker_num(n) {
try {
// 先初始化相关资源,再启动线程
for (int i = 0; i < m_worker_num; i++) {
for (size_t i = 0; i < m_worker_num; i++) {
// 创建工作线程及其任务队列
m_threads_status.push_back(nullptr);
m_queues.push_back(std::unique_ptr<WorkStealQueue>(new WorkStealQueue));
}
for (int i = 0; i < m_worker_num; i++) {
m_threads.push_back(std::thread(&StealThreadPool::worker_thread, this, i));
for (size_t i = 0; i < m_worker_num; i++) {
m_threads.push_back(
std::thread(&StealThreadPool::worker_thread, this, static_cast<int>(i)));
}
} catch (...) {
m_done = true;
@ -244,7 +245,7 @@ private:
bool pop_task_from_other_thread_queue(task_type& task) {
for (size_t i = 0; i < m_worker_num; ++i) {
size_t index = (m_index + i + 1) % m_worker_num;
if (index != m_index && m_queues[index]->try_steal(task)) {
if (int(index) != m_index && m_queues[index]->try_steal(task)) {
return true;
}
}

View File

@ -43,11 +43,12 @@ public:
: m_done(false), m_worker_num(n), m_runnging_util_empty(util_empty) {
try {
// 先初始化相关资源,再启动线程
for (int i = 0; i < m_worker_num; i++) {
for (size_t i = 0; i < m_worker_num; i++) {
m_threads_status.push_back(nullptr);
}
for (int i = 0; i < m_worker_num; i++) {
m_threads.push_back(std::thread(&ThreadPool::worker_thread, this, i));
for (size_t i = 0; i < m_worker_num; i++) {
m_threads.push_back(
std::thread(&ThreadPool::worker_thread, this, static_cast<int>(i)));
}
} catch (...) {
m_done = true;

View File

@ -6,7 +6,7 @@ target("hikyuu")
end
add_packages("fmt", "spdlog", "flatbuffers", "nng", "nlohmann_json", "cpp-httplib")
if is_plat("windows") then
if is_plat("windows", "linux") then
add_packages("sqlite3")
end
@ -39,17 +39,7 @@ target("hikyuu")
end
if is_plat("linux") then
add_packages("hdf5")
if is_arch("x86_64") then
if os.exists("/usr/lib64/mysql") then
add_linkdirs("/usr/lib64/mysql")
end
if os.exists("/usr/lib/x86_64-linux-gnu") then
add_linkdirs("/usr/lib/x86_64-linux-gnu")
end
end
add_links("sqlite3")
add_links("mysqlclient")
add_packages("hdf5", "mysql")
add_links("boost_date_time")
add_links("boost_filesystem")
add_links("boost_serialization")

View File

@ -32,13 +32,20 @@ typedef uint64_t u_int64_t;
#include <stdint.h>
#endif
#define explicit_bzero(s,n) memset(s, 0, n)
#define explicit_bzero(s, n) memset(s, 0, n)
#define DEF_WEAK(f)
#if __cplusplus
extern "C" {
#endif
int bcrypt_hashpass(const char *key, const char *salt, char *encrypted, size_t encryptedlen);
int encode_base64(char *, const u_int8_t *, size_t);
int timingsafe_bcmp(const void *b1, const void *b2, size_t n);
int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, uint8_t *key, size_t keylen, unsigned int rounds);
int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen,
uint8_t *key, size_t keylen, unsigned int rounds);
#if __cplusplus
}
#endif
#endif

View File

@ -26,12 +26,7 @@ target("hkuserver")
end
if is_plat("linux") then
if is_arch("x86_64") then
if os.exists("/usr/lib64/mysql") then
add_linkdirs("/usr/lib64/mysql")
end
add_linkdirs("/usr/lib/x86_64-linux-gnu")
end
add_packages("mysql")
end
if is_plat("macosx") then

View File

@ -12,7 +12,7 @@ package("hdf5")
elseif is_plat("linux") then
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-linux-x64.zip",
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5-$(version)-linux-x64.zip")
add_versions("1.12.2", "8a6b571168481fba273e1f0c7838d417f38222b5d93250388d2ddff5ff7f2611")
add_versions("1.12.2", "e0f4357ea7bfa0132c3edba9b517635736191f920ce7a3aeef5e89dbe5b2dd27")
end
on_load("windows", "linux", function (package)

View File

@ -7,6 +7,7 @@ package("hdf5_D")
if is_plat("windows") then
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5_D-$(version)-win-x64.zip",
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/hdf5_D-$(version)-win-x64.zip")
add_versions("1.12.2", "6ea3ab5a4b0bb0f48eaef28cfe747ac5c072c06519a4888c1a59cfaf75399049")
add_versions("1.10.4", "5b1bd27e054f885bf9cac0beffcacbe180e251c5d8c12c0652a96055f2784b46")
end

View File

@ -7,11 +7,17 @@ package("mysql")
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-win-x64.zip",
"https://gitee.com/fasiondog/hikyuu/attach_files/935339/download/mysql-$(version)-win-x64.zip")
add_versions("8.0.21", "de21694aa230a00b52b28babbce9bb150d990ba1f539edf8d193586dce3844ae")
elseif is_plat("linux") then
add_urls("https://github.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-linux-x86_64.zip",
"https://gitee.com/fasiondog/hikyuu/releases/download/1.1.9/mysql-$(version)-linux-x86_64.zip")
add_versions("8.0.31", "1775a94f4a59cfb03593e6e70891de33a0cc8713573afdfc9ca0482415a8ecd3")
end
on_install("windows", function (package)
on_install("windows", "linux", function (package)
os.cp("include", package:installdir())
os.cp("lib", package:installdir())
os.cp("bin", package:installdir())
if package:is_plat("windows") then
os.cp("bin", package:installdir())
end
end)

View File

@ -17,8 +17,8 @@ struct Constant {
: null_datetime(Null<Datetime>()),
inf(std::numeric_limits<double>::infinity()),
nan(std::numeric_limits<double>::quiet_NaN()),
max_double(std::numeric_limits<double>::max()),
null_double(Null<double>()),
max_double(std::numeric_limits<double>::max()),
null_price(Null<price_t>()),
null_int(Null<int>()),
null_size(Null<size_t>()),

View File

@ -132,7 +132,14 @@ inline void Parameter::set<object>(const string& name, const object& o) {
extract<int> x2(o);
if (x2.check()) {
int overflow;
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
long val = PyLong_AsLongAndOverflow(o.ptr(), &overflow);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
if (overflow == 0) {
m_params[name] = x2();
} else {

View File

@ -123,7 +123,8 @@ def build_boost(mode):
# ' --with-serialization'.format(mode))
os.chdir(current_dir)
else:
cmd = 'cd {boost} ; if [ ! -f "b2" ]; then ./bootstrap.sh ; fi; '\
# 新版的 boost 配置 project-cofig.jam 中的 python 版本无效,必须在当前 python 下重新编译 b2
cmd = 'cd {boost} ; ./bootstrap.sh; '\
'./b2 {mode} link=shared address-model=64 -j 4 --with-python --with-serialization; '\
'./b2 {mode} link=static address-model=64 cxxflags=-fPIC -j 4 --with-date_time '\
'--with-filesystem --with-system --with-test --with-atomic; '\

View File

@ -23,6 +23,7 @@ min5 = False
min15 = False
min30 = False
min60 = False
hour2 = False
day_max = 100000
week_max = 100000
month_max = 100000
@ -34,7 +35,7 @@ min5_max = 5120
min15_max = 5120
min30_max = 5120
min60_max = 5120
hour2_max = 5120
[baseinfo]
type = sqlite3

View File

@ -23,6 +23,7 @@ min5 = False
min15 = False
min30 = False
min60 = False
hour2 = False
day_max = 100000
week_max = 100000
month_max = 100000
@ -34,6 +35,7 @@ min5_max = 5120
min15_max = 5120
min30_max = 5120
min60_max = 5120
hour2_max = 5120
[baseinfo]
type = sqlite3

View File

@ -9,7 +9,7 @@ if not is_plat("windows") then
end
-- version
set_version("1.2.5", {build="%Y%m%d%H%M"})
set_version("1.2.7", {build="%Y%m%d%H%M"})
set_configvar("LOG_ACTIVE_LEVEL", 0) -- 激活的日志级别
--if is_mode("debug") then
-- set_configvar("LOG_ACTIVE_LEVEL", 0) -- 激活的日志级别
@ -40,7 +40,10 @@ end
set_languages("cxx17", "C99")
local hdf5_version = "1.12.2"
local mysql_version = "8.0.21"
local mysql_version = "8.0.31"
if is_plat("windows") then
mysql_version = "8.0.21"
end
add_repositories("project-repo hikyuu_extern_libs")
if is_plat("windows") then
@ -52,26 +55,22 @@ if is_plat("windows") then
end
add_requires("mysql " .. mysql_version)
elseif is_plat("linux") then
add_requires("hdf5 " .. hdf5_version)
add_requires("hdf5 " .. hdf5_version, {system = false})
add_requires("mysql " .. mysql_version, {system = false})
elseif is_plat("macosx") then
add_requires("brew::hdf5")
end
-- add_requires("fmt 8.1.1", {system=false, configs = {header_only = true}})
add_requires("spdlog", {system=false, configs = {header_only = true, fmt_external=true, vs_runtime = "MD"}})
add_requireconfs("spdlog.fmt", {override = true, version = "8.1.1", configs = {header_only = true}})
add_requires("sqlite3", {system=false, configs = {shared=true, vs_runtime="MD", cxflags="-fPIC"}})
add_requires("flatbuffers", {system=false, configs = {vs_runtime="MD"}})
add_requires("nng", {system=false, configs = {vs_runtime="MD", cxflags="-fPIC"}})
add_requires("nlohmann_json", {system=false})
add_requires("cpp-httplib", {system=false})
add_requires("zlib", {system=false})
if is_plat("linux") and linuxos.name() == "ubuntu" then
add_requires("apt::libmysqlclient-dev", "apt::libsqlite3-dev")
elseif is_plat("macosx") then
add_requires("brew::hdf5")
else
add_requires("sqlite3", {configs = {shared=true, vs_runtime="MD", cxflags="-fPIC"}})
end
add_defines("SPDLOG_DISABLE_DEFAULT_LOGGER") -- 禁用 spdlog 默认 logger
set_objectdir("$(buildir)/$(mode)/$(plat)/$(arch)/.objs")
@ -84,15 +83,6 @@ add_linkdirs("$(env BOOST_LIB)")
--add_defines("BOOST_ALL_DYN_LINK")
add_defines("BOOST_SERIALIZATION_DYN_LINK")
if is_host("linux") then
if is_arch("x86_64") then
add_linkdirs("/usr/lib64")
if os.exists("/usr/lib/x86_64-linux-gnu") then
add_linkdirs("/usr/lib/x86_64-linux-gnu")
end
end
end
-- is release now
if is_mode("release") then
if is_plat("windows") then