hikyuu 2.3.0__py3-none-win_amd64.whl → 2.5.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hikyuu/__init__.py +438 -6
- hikyuu/__init__.pyi +791 -0
- hikyuu/analysis/__init__.pyi +487 -0
- hikyuu/analysis/analysis.pyi +517 -0
- hikyuu/core.pyi +482 -0
- hikyuu/cpp/__init__.pyi +3 -0
- hikyuu/cpp/boost_date_time-mt.dll +0 -0
- hikyuu/cpp/boost_serialization-mt.dll +0 -0
- hikyuu/cpp/boost_wserialization-mt.dll +0 -0
- hikyuu/cpp/core310.pyd +0 -0
- hikyuu/cpp/core311.pyd +0 -0
- hikyuu/cpp/core312.pyd +0 -0
- hikyuu/cpp/core312.pyi +12867 -0
- hikyuu/cpp/core313.pyd +0 -0
- hikyuu/cpp/core38.pyd +0 -0
- hikyuu/cpp/core39.pyd +0 -0
- hikyuu/cpp/hikyuu.dll +0 -0
- hikyuu/cpp/hikyuu.lib +0 -0
- hikyuu/cpp/sqlite3.dll +0 -0
- hikyuu/data/common_mysql.py +24 -7
- hikyuu/data/common_pytdx.py +17 -1
- hikyuu/data/em_block_to_mysql.py +3 -2
- hikyuu/data/em_block_to_sqlite.py +8 -3
- hikyuu/data/mysql_upgrade/0025.sql +61 -0
- hikyuu/data/mysql_upgrade/0026.sql +9 -0
- hikyuu/data/sqlite_upgrade/0025.sql +63 -0
- hikyuu/data/sqlite_upgrade/0026.sql +10 -0
- hikyuu/draw/__init__.pyi +35 -0
- hikyuu/draw/drawplot/__init__.py +3 -0
- hikyuu/draw/drawplot/__init__.pyi +134 -0
- hikyuu/draw/drawplot/bokeh_draw.pyi +796 -0
- hikyuu/draw/drawplot/common.pyi +10 -0
- hikyuu/draw/drawplot/echarts_draw.py +219 -24
- hikyuu/draw/drawplot/echarts_draw.pyi +682 -0
- hikyuu/draw/drawplot/matplotlib_draw.py +18 -3
- hikyuu/draw/drawplot/matplotlib_draw.pyi +1101 -0
- hikyuu/draw/elder.pyi +44 -0
- hikyuu/draw/kaufman.pyi +38 -0
- hikyuu/draw/volume.pyi +31 -0
- hikyuu/examples/notebook/Demo/Demo2.ipynb +1 -1
- hikyuu/extend.py +9 -3
- hikyuu/extend.pyi +636 -0
- hikyuu/fetcher/stock/zh_block_em.py +118 -51
- hikyuu/gui/data/EscapetimeThread.py +4 -4
- hikyuu/gui/data/ImportBlockInfoTask.py +3 -2
- hikyuu/gui/data/ImportHistoryFinanceTask.py +2 -0
- hikyuu/gui/data/MainWindow.py +48 -42
- hikyuu/gui/importdata.py +13 -26
- hikyuu/hub.py +2 -4
- hikyuu/hub.pyi +254 -0
- hikyuu/include/hikyuu/DataType.h +5 -0
- hikyuu/include/hikyuu/Stock.h +7 -0
- hikyuu/include/hikyuu/indicator/Indicator.h +8 -1
- hikyuu/include/hikyuu/indicator/Indicator2InImp.h +65 -0
- hikyuu/include/hikyuu/indicator/IndicatorImp.h +4 -3
- hikyuu/include/hikyuu/indicator/build_in.h +12 -0
- hikyuu/include/hikyuu/indicator/crt/ADVANCE.h +3 -1
- hikyuu/include/hikyuu/indicator/crt/CONTEXT.h +2 -2
- hikyuu/include/hikyuu/indicator/crt/CORR.h +4 -2
- hikyuu/include/hikyuu/indicator/crt/COST.h +3 -0
- hikyuu/include/hikyuu/indicator/crt/CYCLE.h +24 -0
- hikyuu/include/hikyuu/indicator/crt/DECLINE.h +3 -1
- hikyuu/include/hikyuu/indicator/crt/DISCARD.h +27 -0
- hikyuu/include/hikyuu/indicator/crt/DMA.h +2 -1
- hikyuu/include/hikyuu/indicator/crt/HSL.h +1 -13
- hikyuu/include/hikyuu/indicator/crt/INBLOCK.h +31 -0
- hikyuu/include/hikyuu/indicator/crt/INDEX.h +60 -0
- hikyuu/include/hikyuu/indicator/crt/INSUM.h +5 -2
- hikyuu/include/hikyuu/indicator/crt/ISINF.h +28 -0
- hikyuu/include/hikyuu/indicator/crt/ISINFA.h +28 -0
- hikyuu/include/hikyuu/indicator/crt/ISNA.h +29 -0
- hikyuu/include/hikyuu/indicator/crt/JUMPDOWN.h +24 -0
- hikyuu/include/hikyuu/indicator/crt/JUMPUP.h +24 -0
- hikyuu/include/hikyuu/indicator/crt/LASTVALUE.h +29 -0
- hikyuu/include/hikyuu/indicator/crt/LIUTONGPAN.h +1 -0
- hikyuu/include/hikyuu/indicator/crt/REPLACE.h +29 -0
- hikyuu/include/hikyuu/indicator/crt/SPEARMAN.h +3 -2
- hikyuu/include/hikyuu/indicator/crt/WINNER.h +38 -0
- hikyuu/include/hikyuu/indicator/imp/IContext.h +1 -1
- hikyuu/include/hikyuu/indicator/imp/ICorr.h +7 -22
- hikyuu/include/hikyuu/indicator/imp/ICost.h +31 -0
- hikyuu/include/hikyuu/indicator/imp/ICycle.h +30 -0
- hikyuu/include/hikyuu/indicator/imp/IDiscard.h +28 -0
- hikyuu/include/hikyuu/indicator/imp/IDma.h +7 -24
- hikyuu/include/hikyuu/indicator/imp/IHsl.h +30 -0
- hikyuu/include/hikyuu/indicator/imp/IInBlock.h +30 -0
- hikyuu/include/hikyuu/indicator/imp/IIndex.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/IIsInf.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/IIsInfa.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/IIsNa.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/IJumpDown.h +24 -0
- hikyuu/include/hikyuu/indicator/imp/IJumpUp.h +24 -0
- hikyuu/include/hikyuu/indicator/imp/ILastValue.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/IReplace.h +26 -0
- hikyuu/include/hikyuu/indicator/imp/ISpearman.h +6 -21
- hikyuu/include/hikyuu/indicator/imp/IWinner.h +26 -0
- hikyuu/include/hikyuu/indicator_talib/imp/TaMavp.h +6 -20
- hikyuu/include/hikyuu/indicator_talib/imp/ta_defines.h +14 -65
- hikyuu/include/hikyuu/indicator_talib/imp/ta_imp.h +54 -90
- hikyuu/include/hikyuu/indicator_talib/ta_crt.h +11 -9
- hikyuu/include/hikyuu/strategy/RunPortfolioInStrategy.h +3 -4
- hikyuu/include/hikyuu/strategy/Strategy.h +4 -5
- hikyuu/include/hikyuu/trade_manage/TradeRecord.h +5 -1
- hikyuu/include/hikyuu/trade_sys/allocatefunds/build_in.h +1 -0
- hikyuu/include/hikyuu/trade_sys/allocatefunds/crt/AF_FixedWeightList.h +22 -0
- hikyuu/include/hikyuu/trade_sys/allocatefunds/imp/FixedWeightListAllocateFunds.h +25 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/MoneyManagerBase.h +17 -4
- hikyuu/include/hikyuu/trade_sys/moneymanager/build_in.h +2 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_FixedCapital.h +6 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_FixedCapitalFunds.h +26 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_FixedCountTps.h +27 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_FixedRisk.h +6 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_FixedUnits.h +6 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/crt/MM_WilliamsFixedRisk.h +7 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/imp/FixedCapitalFundsMM.h +28 -0
- hikyuu/include/hikyuu/trade_sys/moneymanager/imp/FixedCountTpsMM.h +44 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/build_in.h +1 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/crt/MF_Weight.h +30 -0
- hikyuu/include/hikyuu/trade_sys/multifactor/imp/WeightMultiFactor.h +41 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/Portfolio.h +38 -37
- hikyuu/include/hikyuu/trade_sys/portfolio/build_in.h +1 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/crt/PF_Simple.h +25 -1
- hikyuu/include/hikyuu/trade_sys/portfolio/crt/PF_WithoutAF.h +50 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/imp/SimplePortfolio.h +53 -0
- hikyuu/include/hikyuu/trade_sys/portfolio/imp/WithoutAFPortfolio.h +57 -0
- hikyuu/include/hikyuu/trade_sys/selector/imp/MultiFactorSelector.h +7 -0
- hikyuu/include/hikyuu/trade_sys/signal/SignalBase.h +51 -5
- hikyuu/include/hikyuu/trade_sys/signal/build_in.h +2 -0
- hikyuu/include/hikyuu/trade_sys/signal/crt/SG_Bool.h +2 -1
- hikyuu/include/hikyuu/trade_sys/signal/crt/SG_Logic.h +37 -0
- hikyuu/include/hikyuu/trade_sys/signal/crt/SG_OneSide.h +28 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/OneSideSignal.h +46 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AddSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/AddValueSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/DivSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/DivValueSignal.h +22 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/MulSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/MulValueSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorSignal.h +68 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/OperatorValueSignal.h +67 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/SubSignal.h +19 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/SubValueSignal.h +22 -0
- hikyuu/include/hikyuu/trade_sys/signal/imp/logic/__init__.py +1 -0
- hikyuu/include/hikyuu/trade_sys/stoploss/crt/ST_Indicator.h +1 -1
- hikyuu/include/hikyuu/trade_sys/stoploss/imp/IndicatorStoploss.h +3 -4
- hikyuu/include/hikyuu/utilities/FilterNode.h +2 -2
- hikyuu/include/hikyuu/utilities/Log.h +42 -15
- hikyuu/include/hikyuu/utilities/datetime/Datetime.h +1 -1
- hikyuu/include/hikyuu/utilities/datetime/TimeDelta.h +2 -2
- hikyuu/include/hikyuu/utilities/db_connect/DBCondition.h +4 -0
- hikyuu/include/hikyuu/utilities/db_connect/SQLResultSet.h +2 -2
- hikyuu/include/hikyuu/utilities/db_connect/mysql/MySQLConnect.h +5 -1
- hikyuu/include/hikyuu/utilities/node/NodeServer.h +4 -4
- hikyuu/include/hikyuu/utilities/thread/MQStealThreadPool.h +2 -2
- hikyuu/include/hikyuu/utilities/thread/MQThreadPool.h +2 -2
- hikyuu/include/hikyuu/utilities/thread/StealThreadPool.h +5 -5
- hikyuu/include/hikyuu/utilities/thread/ThreadPool.h +2 -2
- hikyuu/include/hikyuu/utilities/thread/algorithm.h +16 -10
- hikyuu/include/hikyuu/version.h +4 -4
- hikyuu/indicator/indicator.py +1 -0
- hikyuu/interactive.py +3 -266
- hikyuu/trade_manage/__init__.pyi +584 -0
- hikyuu/trade_manage/broker.pyi +54 -0
- hikyuu/trade_manage/broker_easytrader.pyi +21 -0
- hikyuu/trade_manage/broker_mail.pyi +55 -0
- hikyuu/trade_manage/trade.pyi +590 -0
- hikyuu/util/__init__.pyi +55 -0
- hikyuu/util/check.pyi +59 -0
- hikyuu/util/mylog.pyi +70 -0
- hikyuu/util/notebook.pyi +23 -0
- hikyuu/util/singleton.pyi +18 -0
- hikyuu/util/slice.pyi +8 -0
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/METADATA +3 -2
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/RECORD +178 -95
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/top_level.txt +1 -0
- hikyuu/deprecated.py +0 -651
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/LICENSE +0 -0
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/WHEEL +0 -0
- {hikyuu-2.3.0.dist-info → hikyuu-2.5.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
|
|
3
3
|
from pyecharts import options as opts
|
|
4
|
-
from pyecharts.charts import Kline, Scatter, Line, Bar, Grid
|
|
4
|
+
from pyecharts.charts import Kline, Scatter, Line, Bar, Grid, Page
|
|
5
5
|
from pyecharts.charts.base import Base as ChartBase
|
|
6
6
|
from pyecharts.commons.utils import JsCode
|
|
7
7
|
|
|
@@ -9,6 +9,92 @@ from hikyuu.core import KData, System
|
|
|
9
9
|
from .common import get_draw_title
|
|
10
10
|
from hikyuu import *
|
|
11
11
|
|
|
12
|
+
|
|
13
|
+
class MultiLineTextChart(ChartBase):
|
|
14
|
+
def __init__(self, init_opts: opts.InitOpts = opts.InitOpts()):
|
|
15
|
+
super().__init__(init_opts=init_opts)
|
|
16
|
+
self._last_x = 50 # 默认起始 x 坐标
|
|
17
|
+
self._last_y = 5 # 默认起始 y 坐标
|
|
18
|
+
self._line_height = 20 # 默认行高
|
|
19
|
+
|
|
20
|
+
def reset_position(self, x=None, y=None):
|
|
21
|
+
if x is not None:
|
|
22
|
+
self._last_x = x
|
|
23
|
+
if y is not None:
|
|
24
|
+
self._last_y = y
|
|
25
|
+
|
|
26
|
+
def add(self, text: str, x = None, y = None, text_style = None):
|
|
27
|
+
"""
|
|
28
|
+
添加多行文本
|
|
29
|
+
|
|
30
|
+
:param text: 要显示的文本内容
|
|
31
|
+
:param x: 文本区域的左上角 x 坐标
|
|
32
|
+
:param y: 文本区域的左上角 y 坐标
|
|
33
|
+
:param text_style: 文本样式,如字体大小、颜色等
|
|
34
|
+
"""
|
|
35
|
+
if text_style is None:
|
|
36
|
+
text_style = {"fontSize": 14, "color": "#333", "fontFamily": "Arial"}
|
|
37
|
+
|
|
38
|
+
graphic_elements = self.options.get('graphic', [])
|
|
39
|
+
|
|
40
|
+
if x is None:
|
|
41
|
+
x = self._last_x
|
|
42
|
+
if y is None:
|
|
43
|
+
y = self._last_y + self._line_height
|
|
44
|
+
|
|
45
|
+
# 默认左右边距各50
|
|
46
|
+
width = int(self.width.strip('px')) - 100
|
|
47
|
+
if x is not None:
|
|
48
|
+
width -= x
|
|
49
|
+
lines = self._split_text(text, width, text_style.get("font_size", 14))
|
|
50
|
+
|
|
51
|
+
for i, line in enumerate(lines):
|
|
52
|
+
graphic_elements.append(
|
|
53
|
+
opts.GraphicText(
|
|
54
|
+
graphic_item=opts.GraphicItem(
|
|
55
|
+
position=[x, y + i * (text_style.get("font_size", 14) + 5)],
|
|
56
|
+
z=100,
|
|
57
|
+
),
|
|
58
|
+
graphic_textstyle_opts=opts.GraphicTextStyleOpts(
|
|
59
|
+
text=line,
|
|
60
|
+
font=text_style.get("fontFamily", "sans-serif"),
|
|
61
|
+
font_size=text_style.get("font_size", 14),
|
|
62
|
+
graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
|
|
63
|
+
fill=text_style.get("color", "#000"))
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
self._last_x = x
|
|
68
|
+
self._last_y = y + i * (text_style.get("font_size", 14) + 5)
|
|
69
|
+
|
|
70
|
+
self.options.update(graphic=graphic_elements)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _split_text(self, text: str, width: int, font_size: int):
|
|
74
|
+
"""
|
|
75
|
+
根据宽度和字体大小分割文本为多行
|
|
76
|
+
|
|
77
|
+
:param text: 要分割的文本
|
|
78
|
+
:param width: 文本区域的宽度
|
|
79
|
+
:param font_size: 字体大小
|
|
80
|
+
:return: 分割后的文本行列表
|
|
81
|
+
"""
|
|
82
|
+
# 假设每个字符的宽度大致为字体大小的一半
|
|
83
|
+
max_chars_per_line = int(width / (font_size / 2))
|
|
84
|
+
lines = []
|
|
85
|
+
current_line = ""
|
|
86
|
+
for word in text.split():
|
|
87
|
+
if len(current_line) + len(word) + 1 <= max_chars_per_line:
|
|
88
|
+
current_line += " " + word if current_line else word
|
|
89
|
+
else:
|
|
90
|
+
if current_line:
|
|
91
|
+
lines.append(current_line)
|
|
92
|
+
current_line = word
|
|
93
|
+
if current_line:
|
|
94
|
+
lines.append(current_line)
|
|
95
|
+
return lines
|
|
96
|
+
|
|
97
|
+
|
|
12
98
|
# 控制k线图和volume图的位置
|
|
13
99
|
grid_pos = [
|
|
14
100
|
opts.GridOpts(pos_left="5%", pos_right="1%", height="57%"),
|
|
@@ -17,12 +103,12 @@ grid_pos = [
|
|
|
17
103
|
|
|
18
104
|
|
|
19
105
|
def _get_js_data_var(kdata):
|
|
20
|
-
datas = [[r.open, r.close, r.low, r.high, r.volume] for r in kdata]
|
|
106
|
+
datas = [[round(r.open, 2), round(r.close, 2), round(r.low, 2), round(r.high, 2), round(r.volume, 2)] for r in kdata]
|
|
21
107
|
return datas
|
|
22
108
|
|
|
23
109
|
|
|
24
110
|
def _brush_chart(kdata, chart):
|
|
25
|
-
datetimes_str =
|
|
111
|
+
datetimes_str = simple_datetime_list(kdata.get_datetime_list(), kdata.get_query().ktype)
|
|
26
112
|
brush_range = (datetimes_str[len(datetimes_str) // 2], datetimes_str[len(datetimes_str) * 3 // 4])
|
|
27
113
|
if hasattr(chart, 'add_dispatch_actions'): # PR https://github.com/pyecharts/pyecharts/pull/2244 not yet merged
|
|
28
114
|
chart.add_dispatch_actions(
|
|
@@ -66,11 +152,25 @@ def get_series_name(kdata):
|
|
|
66
152
|
return stitle
|
|
67
153
|
|
|
68
154
|
|
|
155
|
+
def simple_datetime_list(datetimes: list, ktype:str=None):
|
|
156
|
+
if ktype is None:
|
|
157
|
+
return [
|
|
158
|
+
sd.split(' ')[0] if sd.endswith('00:00:00') else
|
|
159
|
+
sd.rsplit(':', 1)[0] if sd.endswith(':00') else
|
|
160
|
+
sd
|
|
161
|
+
for sd in (str(dt) for dt in datetimes)
|
|
162
|
+
]
|
|
163
|
+
if ktype.startswith('MIN') or ktype.startswith('HOUR'):
|
|
164
|
+
datetimes = [str(dt).rsplit(':', 1)[0] for dt in datetimes]
|
|
165
|
+
else:
|
|
166
|
+
datetimes = [str(dt).split(' ')[0] for dt in datetimes]
|
|
167
|
+
return datetimes
|
|
168
|
+
|
|
169
|
+
|
|
69
170
|
def kplot_line(kdata: KData):
|
|
70
|
-
datetimes = kdata.get_datetime_list()
|
|
71
|
-
datetimes = [str(dt) for dt in datetimes]
|
|
171
|
+
datetimes = simple_datetime_list(kdata.get_datetime_list(), kdata.get_query().ktype)
|
|
72
172
|
# order in OCLH
|
|
73
|
-
kdata_points = [(r.open, r.close, r.low, r.high) for r in kdata]
|
|
173
|
+
kdata_points = [(round(r.open, 2), round(r.close, 2), round(r.low, 2), round(r.high, 2)) for r in kdata]
|
|
74
174
|
title = get_draw_title(kdata)
|
|
75
175
|
last_record = kdata[-1]
|
|
76
176
|
text = u'%s 开:%.2f 高:%.2f 低:%.2f 收:%.2f 涨幅:%.2f%%' % (
|
|
@@ -92,11 +192,11 @@ def kplot_line(kdata: KData):
|
|
|
92
192
|
),
|
|
93
193
|
datazoom_opts=[
|
|
94
194
|
opts.DataZoomOpts(
|
|
95
|
-
is_show=
|
|
195
|
+
is_show=len(datetimes) > 200,
|
|
96
196
|
xaxis_index=[0, 1], # 同时控制k线图和volume图的x轴缩放
|
|
97
197
|
type_="slider",
|
|
98
198
|
pos_top="85%",
|
|
99
|
-
range_start=0,
|
|
199
|
+
range_start=(100 - 200 * 100 / len(datetimes)) if len(datetimes) > 200 else 0,
|
|
100
200
|
range_end=100,
|
|
101
201
|
),
|
|
102
202
|
],
|
|
@@ -163,8 +263,7 @@ def kplot_line(kdata: KData):
|
|
|
163
263
|
|
|
164
264
|
|
|
165
265
|
def volume_barplot(kdata: KData):
|
|
166
|
-
datetimes = kdata.get_datetime_list()
|
|
167
|
-
datetimes = [str(dt) for dt in datetimes]
|
|
266
|
+
datetimes = simple_datetime_list(kdata.get_datetime_list(), kdata.get_query().ktype)
|
|
168
267
|
volumes = [r.volume for r in kdata]
|
|
169
268
|
bar_vol = (
|
|
170
269
|
Bar()
|
|
@@ -212,15 +311,15 @@ def volume_barplot(kdata: KData):
|
|
|
212
311
|
|
|
213
312
|
|
|
214
313
|
@_chart_html_wrap
|
|
215
|
-
def iplot(indicator, kref: KData = None, chart=None):
|
|
314
|
+
def iplot(indicator, kref: KData = None, chart=None, ilongname=False):
|
|
216
315
|
datetimes = indicator.get_datetime_list()
|
|
217
|
-
py_indicator = [None if x == constant.null_price else x for x in indicator]
|
|
218
|
-
datetimes =
|
|
316
|
+
py_indicator = [None if x == constant.null_price else round(x, 2) for x in indicator]
|
|
317
|
+
datetimes = simple_datetime_list(datetimes)
|
|
219
318
|
if not datetimes:
|
|
220
319
|
datetimes = list(range(len(indicator)))
|
|
221
320
|
if kref:
|
|
222
|
-
datetimes =
|
|
223
|
-
name =
|
|
321
|
+
datetimes = simple_datetime_list(kref.get_datetime_list(), kref.get_query().ktype)
|
|
322
|
+
name = indicator.name
|
|
224
323
|
line = (
|
|
225
324
|
Line()
|
|
226
325
|
.add_xaxis(xaxis_data=datetimes)
|
|
@@ -236,6 +335,7 @@ def iplot(indicator, kref: KData = None, chart=None):
|
|
|
236
335
|
return chart.overlap(line)
|
|
237
336
|
else:
|
|
238
337
|
line.set_global_opts(
|
|
338
|
+
title_opts=opts.TitleOpts(title="%s %.2f" % (indicator.long_name if ilongname else indicator.name, indicator[-1])),
|
|
239
339
|
yaxis_opts=opts.AxisOpts(
|
|
240
340
|
is_scale=True,
|
|
241
341
|
splitarea_opts=opts.SplitAreaOpts(
|
|
@@ -250,6 +350,16 @@ def iplot(indicator, kref: KData = None, chart=None):
|
|
|
250
350
|
border_color="#ccc",
|
|
251
351
|
textstyle_opts=opts.TextStyleOpts(color="#000"),
|
|
252
352
|
),
|
|
353
|
+
datazoom_opts=[
|
|
354
|
+
opts.DataZoomOpts(
|
|
355
|
+
is_show=len(datetimes) > 200,
|
|
356
|
+
xaxis_index=0,
|
|
357
|
+
type_="slider",
|
|
358
|
+
pos_top="92%",
|
|
359
|
+
range_start=(100 - 200 * 100 / len(datetimes)) if len(datetimes) > 200 else 0,
|
|
360
|
+
range_end=100,
|
|
361
|
+
)
|
|
362
|
+
],
|
|
253
363
|
)
|
|
254
364
|
return line
|
|
255
365
|
|
|
@@ -257,12 +367,12 @@ def iplot(indicator, kref: KData = None, chart=None):
|
|
|
257
367
|
@_chart_html_wrap
|
|
258
368
|
def ibar(indicator, kref: KData = None, chart=None):
|
|
259
369
|
datetimes = indicator.get_datetime_list()
|
|
260
|
-
py_indicator = [None if x == constant.null_price else x for x in indicator]
|
|
261
|
-
datetimes =
|
|
370
|
+
py_indicator = [None if x == constant.null_price else round(x, 2) for x in indicator]
|
|
371
|
+
datetimes = simple_datetime_list(datetimes)
|
|
262
372
|
if not datetimes:
|
|
263
373
|
datetimes = list(range(len(indicator)))
|
|
264
374
|
if kref:
|
|
265
|
-
datetimes =
|
|
375
|
+
datetimes = simple_datetime_list(kref.get_datetime_list(), kref.get_query().ktype)
|
|
266
376
|
name = "%s %.2f" % (indicator.long_name, indicator[-1])
|
|
267
377
|
bar = (
|
|
268
378
|
Bar()
|
|
@@ -288,9 +398,19 @@ def ibar(indicator, kref: KData = None, chart=None):
|
|
|
288
398
|
|
|
289
399
|
|
|
290
400
|
@_chart_html_wrap
|
|
291
|
-
def kplot(kdata: KData):
|
|
401
|
+
def kplot(kdata: KData, ind_main=None, ind_sub=None):
|
|
292
402
|
kline = kplot_line(kdata)
|
|
403
|
+
if ind_main is not None:
|
|
404
|
+
if isinstance(ind_main, Indicator):
|
|
405
|
+
ind_main = [ind_main]
|
|
406
|
+
for ind in ind_main:
|
|
407
|
+
kline = iplot(ind, kdata, kline)
|
|
293
408
|
vol_bar = volume_barplot(kdata)
|
|
409
|
+
if ind_sub is not None:
|
|
410
|
+
if isinstance(ind_sub, Indicator):
|
|
411
|
+
ind_sub = [ind_sub]
|
|
412
|
+
for ind in ind_sub:
|
|
413
|
+
vol_bar = iplot(ind, kdata, vol_bar)
|
|
294
414
|
grid_chart = Grid()
|
|
295
415
|
grid_chart.add_js_funcs("var barData = {}".format(_get_js_data_var(kdata)))
|
|
296
416
|
grid_chart.add(
|
|
@@ -301,6 +421,8 @@ def kplot(kdata: KData):
|
|
|
301
421
|
vol_bar,
|
|
302
422
|
grid_opts=grid_pos[1],
|
|
303
423
|
)
|
|
424
|
+
grid_chart.g1rootchart = kline
|
|
425
|
+
grid_chart.g2rootchart = vol_bar
|
|
304
426
|
_brush_chart(kdata, grid_chart)
|
|
305
427
|
return grid_chart
|
|
306
428
|
|
|
@@ -308,7 +430,7 @@ def kplot(kdata: KData):
|
|
|
308
430
|
@_chart_html_wrap
|
|
309
431
|
def sysplot(sys: System):
|
|
310
432
|
kdata = sys.to
|
|
311
|
-
datetimes = kdata.get_datetime_list()
|
|
433
|
+
datetimes = simple_datetime_list(kdata.get_datetime_list(), kdata.get_query().ktype)
|
|
312
434
|
date_index = dict([(d, i) for i, d in enumerate(datetimes)])
|
|
313
435
|
|
|
314
436
|
kline = kplot_line(kdata)
|
|
@@ -323,10 +445,12 @@ def sysplot(sys: System):
|
|
|
323
445
|
sell_dates.append(t.datetime)
|
|
324
446
|
else:
|
|
325
447
|
pass
|
|
448
|
+
buy_dates = simple_datetime_list(buy_dates, kdata.get_query().ktype)
|
|
449
|
+
sell_dates = simple_datetime_list(sell_dates, kdata.get_query().ktype)
|
|
326
450
|
|
|
327
451
|
buy_pos = []
|
|
328
452
|
sell_pos = []
|
|
329
|
-
closep = [d.close for d in kdata]
|
|
453
|
+
closep = [round(d.close, 2) for d in kdata]
|
|
330
454
|
candle_gap = (max(closep) - min(closep)) * 0.05
|
|
331
455
|
|
|
332
456
|
for d in buy_dates:
|
|
@@ -339,9 +463,6 @@ def sysplot(sys: System):
|
|
|
339
463
|
continue
|
|
340
464
|
sell_pos.append(kdata[date_index[d]].high + candle_gap)
|
|
341
465
|
|
|
342
|
-
buy_dates = [str(dt) for dt in buy_dates]
|
|
343
|
-
sell_dates = [str(dt) for dt in sell_dates]
|
|
344
|
-
|
|
345
466
|
buy_scatter = (
|
|
346
467
|
Scatter()
|
|
347
468
|
.add_xaxis(buy_dates)
|
|
@@ -400,3 +521,77 @@ def sysplot(sys: System):
|
|
|
400
521
|
)
|
|
401
522
|
_brush_chart(kdata, grid_chart)
|
|
402
523
|
return grid_chart
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def sys_performance(sys, ref_stk=None):
|
|
527
|
+
if ref_stk is None:
|
|
528
|
+
ref_stk = get_stock('sh000300')
|
|
529
|
+
|
|
530
|
+
query = sys.query
|
|
531
|
+
sh000001_k = get_kdata('sh000001', query)
|
|
532
|
+
ref_dates = sh000001_k.get_datetime_list()
|
|
533
|
+
|
|
534
|
+
ref_k = ref_stk.get_kdata(query)
|
|
535
|
+
|
|
536
|
+
funds_list = sys.tm.get_funds_list(ref_dates)
|
|
537
|
+
funds = [f.total_assets for f in funds_list]
|
|
538
|
+
funds = VALUE(funds)
|
|
539
|
+
funds_return = [f.total_assets / f.total_base if f.total_base != 0.0 else constant.null_price for f in funds_list]
|
|
540
|
+
funds_return = VALUE(funds_return, align_dates=ref_dates)
|
|
541
|
+
funds_return.name = "系统累积收益率"
|
|
542
|
+
ref_return = ALIGN(ROCR(ref_k.close, 0), ref_dates)
|
|
543
|
+
ref_return.name = f"{ref_stk.name}({ref_stk.market_code})"
|
|
544
|
+
|
|
545
|
+
per = Performance()
|
|
546
|
+
text = per.report(sys.tm, sh000001_k[-1].datetime)
|
|
547
|
+
|
|
548
|
+
# 计算最大回撤
|
|
549
|
+
max_pullback = min(MDD(funds).to_np())
|
|
550
|
+
|
|
551
|
+
# 计算 sharp
|
|
552
|
+
bond = ZHBOND10(ref_dates)
|
|
553
|
+
sigma = STDEV(ROCP(funds), len(ref_dates))
|
|
554
|
+
sigma = 15.874507866387544 * sigma[-1] # 15.874 = sqrt(252)
|
|
555
|
+
sharp = (per['帐户平均年收益率%'] - bond[-1]) * 0.01 / sigma if sigma != 0.0 else 0.0
|
|
556
|
+
|
|
557
|
+
invest_total = per['累计投入本金'] + per['累计投入资产']
|
|
558
|
+
cur_fund = per['当前总资产']
|
|
559
|
+
t1 = '投入总资产: {:<.2f} 当前总资产: {:<.2f} 当前盈利: {:<.2f}'.format(
|
|
560
|
+
invest_total, cur_fund, cur_fund - invest_total)
|
|
561
|
+
t2 = '当前策略收益: {:<.2f}% 年化收益率: {:<.2f}% 最大回撤: {:<.2f}%'.format(
|
|
562
|
+
funds_return[-1]*100 - 100, per["帐户平均年收益率%"], max_pullback)
|
|
563
|
+
t3 = '系统胜率: {:<.2f}% 盈/亏比: 1 : {:<.2f} 夏普比率: {:<.2f}'.format(
|
|
564
|
+
per['赢利交易比例%'], per['净赢利/亏损比例'], sharp)
|
|
565
|
+
|
|
566
|
+
line = iplot(ref_return, ref_k)
|
|
567
|
+
line = iplot(funds_return, ref_k, line)
|
|
568
|
+
line.get_options().update(dataZoom=[
|
|
569
|
+
opts.DataZoomOpts(
|
|
570
|
+
is_show=len(ref_dates) > 500,
|
|
571
|
+
xaxis_index=0,
|
|
572
|
+
type_="slider",
|
|
573
|
+
pos_top="92%",
|
|
574
|
+
range_start=(100 - 500 * 100 / len(ref_dates)) if len(ref_dates) > 500 else 0,
|
|
575
|
+
range_end=100,
|
|
576
|
+
),
|
|
577
|
+
])
|
|
578
|
+
|
|
579
|
+
page = Page()
|
|
580
|
+
page.add(line)
|
|
581
|
+
|
|
582
|
+
tchart = MultiLineTextChart(opts.InitOpts(height='65px'))
|
|
583
|
+
tchart.add(t1, y = 5)
|
|
584
|
+
tchart.add(t2)
|
|
585
|
+
tchart.add(t3)
|
|
586
|
+
page.add(tchart)
|
|
587
|
+
|
|
588
|
+
txchart = MultiLineTextChart(opts.InitOpts(height='550px'))
|
|
589
|
+
tlines = text.splitlines()
|
|
590
|
+
tlcount = len(tlines)
|
|
591
|
+
for i in range(tlcount//2):
|
|
592
|
+
txchart.add(tlines[i])
|
|
593
|
+
txchart.reset_position(y=5)
|
|
594
|
+
for i in range(tlcount//2, tlcount):
|
|
595
|
+
txchart.add(tlines[i], x=400)
|
|
596
|
+
page.add(txchart)
|
|
597
|
+
return page
|