VeighNa量化社区
你的开源社区量化交易平台
hxxjava's Avatar
Member
离线
419 帖子
声望: 155

看完了陈老师的线上公开课,化了2天时间终于把MACD幅图曲线给添加上了。
MACD曲线和RSI,SMA之类的不同之处在于它的y方向显示范围是可变的,需要根据K线显示范围的变化及时做出调整,有执行效率问题。
本人采用了字典保存了已经计算的y方向显示范围计算结果,避免了重复计算,执行效率还是相当流畅的。当然会需要一定的存储开销,但
是不大,而且也是值得开销的。代码如下:

from datetime import datetime
from typing import List, Tuple, Dict

import numpy as np
import pyqtgraph as pg
import talib
import copy

from vnpy.trader.ui import create_qapp, QtCore, QtGui, QtWidgets
from vnpy.trader.database import database_manager
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.object import BarData

from vnpy.chart import ChartWidget, VolumeItem, CandleItem
from vnpy.chart.item import ChartItem
from vnpy.chart.manager import BarManager
from vnpy.chart.base import NORMAL_FONT


class LineItem(CandleItem):
    """"""

    def __init__(self, manager: BarManager):
        """"""
        super().__init__(manager)

        self.white_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 255), width=1)

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
        """"""
        last_bar = self._manager.get_bar(ix - 1)

        # Create objects
        picture = QtGui.QPicture()
        painter = QtGui.QPainter(picture)

        # Set painter color
        painter.setPen(self.white_pen)

        # Draw Line
        end_point = QtCore.QPointF(ix, bar.close_price)

        if last_bar:
            start_point = QtCore.QPointF(ix - 1, last_bar.close_price)
        else:
            start_point = end_point

        painter.drawLine(start_point, end_point)

        # Finish
        painter.end()
        return picture


class SmaItem(CandleItem):
    """"""

    def __init__(self, manager: BarManager):
        """"""
        super().__init__(manager)

        self.blue_pen: QtGui.QPen = pg.mkPen(color=(100, 100, 255), width=2)

        self.sma_window = 10
        self.sma_data: Dict[int, float] = {}

    def get_sma_value(self, ix: int) -> float:
        """"""
        if ix < 0:
            return 0

        # When initialize, calculate all rsi value
        if not self.sma_data:
            bars = self._manager.get_all_bars()
            close_data = [bar.close_price for bar in bars]
            sma_array = talib.SMA(np.array(close_data), self.sma_window)

            for n, value in enumerate(sma_array):
                self.sma_data[n] = value

        # Return if already calcualted
        if ix in self.sma_data:
            return self.sma_data[ix]

        # Else calculate new value
        close_data = []
        for n in range(ix - self.sma_window, ix + 1):
            bar = self._manager.get_bar(n)
            close_data.append(bar.close_price)

        sma_array = talib.SMA(np.array(close_data), self.sma_window)
        sma_value = sma_array[-1]
        self.sma_data[ix] = sma_value

        return sma_value

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
        """"""
        sma_value = self.get_sma_value(ix)
        last_sma_value = self.get_sma_value(ix - 1)

        # Create objects
        picture = QtGui.QPicture()
        painter = QtGui.QPainter(picture)

        # Set painter color
        painter.setPen(self.blue_pen)

        # Draw Line
        start_point = QtCore.QPointF(ix-1, last_sma_value)
        end_point = QtCore.QPointF(ix, sma_value)
        painter.drawLine(start_point, end_point)

        # Finish
        painter.end()
        return picture

    def get_info_text(self, ix: int) -> str:
        """"""
        if ix in self.sma_data:
            sma_value = self.sma_data[ix]
            text = f"SMA {sma_value:.1f}"
        else:
            text = "SMA -"

        return text


class RsiItem(ChartItem):
    """"""

    def __init__(self, manager: BarManager):
        """"""
        super().__init__(manager)

        self.white_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 255), width=1)
        self.yellow_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 0), width=2)

        self.rsi_window = 14
        self.rsi_data: Dict[int, float] = {}

    def get_rsi_value(self, ix: int) -> float:
        """"""
        if ix < 0:
            return 50

        # When initialize, calculate all rsi value
        if not self.rsi_data:
            bars = self._manager.get_all_bars()
            close_data = [bar.close_price for bar in bars]
            rsi_array = talib.RSI(np.array(close_data), self.rsi_window)

            for n, value in enumerate(rsi_array):
                self.rsi_data[n] = value

        # Return if already calcualted
        if ix in self.rsi_data:
            return self.rsi_data[ix]

        # Else calculate new value
        close_data = []
        for n in range(ix - self.rsi_window, ix + 1):
            bar = self._manager.get_bar(n)
            close_data.append(bar.close_price)

        rsi_array = talib.RSI(np.array(close_data), self.rsi_window)
        rsi_value = rsi_array[-1]
        self.rsi_data[ix] = rsi_value

        return rsi_value

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
        """"""
        rsi_value = self.get_rsi_value(ix)
        last_rsi_value = self.get_rsi_value(ix - 1)

        # Create objects
        picture = QtGui.QPicture()
        painter = QtGui.QPainter(picture)

        # Draw RSI line
        painter.setPen(self.yellow_pen)

        if np.isnan(last_rsi_value) or np.isnan(rsi_value):
            # print(ix - 1, last_rsi_value,ix, rsi_value,)
            pass
        else:
            end_point = QtCore.QPointF(ix, rsi_value)
            start_point = QtCore.QPointF(ix - 1, last_rsi_value)
            painter.drawLine(start_point, end_point)

        # Draw oversold/overbought line
        painter.setPen(self.white_pen)

        painter.drawLine(
            QtCore.QPointF(ix, 70),
            QtCore.QPointF(ix - 1, 70),
        )

        painter.drawLine(
            QtCore.QPointF(ix, 30),
            QtCore.QPointF(ix - 1, 30),
        )

        # Finish
        painter.end()
        return picture

    def boundingRect(self) -> QtCore.QRectF:
        """"""
        # min_price, max_price = self._manager.get_price_range()
        rect = QtCore.QRectF(
            0,
            0,
            len(self._bar_picutures),
            100
        )
        return rect

    def get_y_range( self, min_ix: int = None, max_ix: int = None) -> Tuple[float, float]:
        """  """
        return 0, 100

    def get_info_text(self, ix: int) -> str:
        """"""
        if ix in self.rsi_data:
            rsi_value = self.rsi_data[ix]
            text = f"RSI {rsi_value:.1f}"
            # print(text)
        else:
            text = "RSI -"

        return text


def to_int(value: float) -> int:
    """"""
    return int(round(value, 0))

""" 将y方向的显示范围扩大到1.1 """
def adjust_range(in_range:Tuple[float, float])->Tuple[float, float]:
    ret_range:Tuple[float, float]
    diff = abs(in_range[0] - in_range[1])
    ret_range = (in_range[0]-diff*0.05,in_range[1]+diff*0.05)
    return ret_range

class MacdItem(ChartItem):
    """"""
    _values_ranges: Dict[Tuple[int, int], Tuple[float, float]] = {}

    last_range:Tuple[int, int] = (-1,-1)    # 最新显示K线索引范围

    def __init__(self, manager: BarManager):
        """"""
        super().__init__(manager)

        self.white_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 255), width=1)
        self.yellow_pen: QtGui.QPen = pg.mkPen(color=(255, 255, 0), width=1)
        self.red_pen: QtGui.QPen = pg.mkPen(color=(255, 0, 0), width=1)
        self.green_pen: QtGui.QPen = pg.mkPen(color=(0, 255, 0), width=1)

        self.short_window = 12
        self.long_window = 26
        self.M = 9

        self.macd_data: Dict[int, Tuple[float,float,float]] = {}

    def get_macd_value(self, ix: int) -> Tuple[float,float,float]:
        """"""
        if ix < 0:
            return (0.0,0.0,0.0)

        # When initialize, calculate all macd value
        if not self.macd_data:
            bars = self._manager.get_all_bars()
            close_data = [bar.close_price for bar in bars]

            diffs,deas,macds = talib.MACD(np.array(close_data), 
                                    fastperiod=self.short_window, 
                                    slowperiod=self.long_window, 
                                    signalperiod=self.M)

            for n in range(0,len(diffs)):
                self.macd_data[n] = (diffs[n],deas[n],macds[n])

        # Return if already calcualted
        if ix in self.macd_data:
            return self.macd_data[ix]

        # Else calculate new value
        close_data = []
        for n in range(ix-self.long_window-self.M+1, ix + 1):
            bar = self._manager.get_bar(n)
            close_data.append(bar.close_price)

        diffs,deas,macds = talib.MACD(np.array(close_data), 
                                            fastperiod=self.short_window, 
                                            slowperiod=self.long_window, 
                                            signalperiod=self.M) 
        diff,dea,macd = diffs[-1],deas[-1],macds[-1]
        self.macd_data[ix] = (diff,dea,macd)

        return (diff,dea,macd)

    def _draw_bar_picture(self, ix: int, bar: BarData) -> QtGui.QPicture:
        """"""
        macd_value = self.get_macd_value(ix)
        last_macd_value = self.get_macd_value(ix - 1)

        # # Create objects
        picture = QtGui.QPicture()
        painter = QtGui.QPainter(picture)

        # # Draw macd lines
        if np.isnan(macd_value[0]) or np.isnan(last_macd_value[0]):
            # print("略过macd lines0")
            pass
        else:
            end_point0 = QtCore.QPointF(ix, macd_value[0])
            start_point0 = QtCore.QPointF(ix - 1, last_macd_value[0])
            painter.setPen(self.white_pen)
            painter.drawLine(start_point0, end_point0)

        if np.isnan(macd_value[1]) or np.isnan(last_macd_value[1]):
            # print("略过macd lines1")
            pass
        else:
            end_point1 = QtCore.QPointF(ix, macd_value[1])
            start_point1 = QtCore.QPointF(ix - 1, last_macd_value[1])
            painter.setPen(self.yellow_pen)
            painter.drawLine(start_point1, end_point1)

        if not np.isnan(macd_value[2]):
            if (macd_value[2]>0):
                painter.setPen(self.red_pen)
                painter.setBrush(pg.mkBrush(255,0,0))
            else:
                painter.setPen(self.green_pen)
                painter.setBrush(pg.mkBrush(0,255,0))
            painter.drawRect(QtCore.QRectF(ix-0.3,0,0.6,macd_value[2]))
        else:
            # print("略过macd lines2")
            pass

        painter.end()
        return picture

    def boundingRect(self) -> QtCore.QRectF:
        """"""
        min_y, max_y = self.get_y_range()
        rect = QtCore.QRectF(
            0,
            min_y,
            len(self._bar_picutures),
            max_y
        )
        return rect

    def get_y_range(self, min_ix: int = None, max_ix: int = None) -> Tuple[float, float]:
        #   获得3个指标在y轴方向的范围   
        #   hxxjava 修改,2020-6-29
        #   当显示范围改变时,min_ix,max_ix的值不为None,当显示范围不变时,min_ix,max_ix的值不为None,

        offset = max(self.short_window,self.long_window) + self.M - 1

        if not self.macd_data or len(self.macd_data) < offset:
            return 0.0, 1.0

        # print("len of range dict:",len(self._values_ranges),",macd_data:",len(self.macd_data),(min_ix,max_ix))

        if min_ix != None:          # 调整最小K线索引
            min_ix = max(min_ix,offset)

        if max_ix != None:          # 调整最大K线索引
            max_ix = min(max_ix, len(self.macd_data)-1)

        last_range = (min_ix,max_ix)    # 请求的最新范围   

        if last_range == (None,None):   # 当显示范围不变时
            if self.last_range in self._values_ranges:  
                # 如果y方向范围已经保存
                # 读取y方向范围
                result = self._values_ranges[self.last_range]
                # print("1:",self.last_range,result)
                return adjust_range(result)
            else:
                # 如果y方向范围没有保存
                # 从macd_data重新计算y方向范围
                min_ix,max_ix = 0,len(self.macd_data)-1

                macd_list = list(self.macd_data.values())[min_ix:max_ix + 1]
                ndarray = np.array(macd_list)           
                max_price = np.nanmax(ndarray)
                min_price = np.nanmin(ndarray)

                # 保存y方向范围,同时返回结果
                result = (min_price, max_price)
                self.last_range = (min_ix,max_ix)
                self._values_ranges[self.last_range] = result
                # print("2:",self.last_range,result)
                return adjust_range(result)

        """ 以下为显示范围变化时 """

        if last_range in self._values_ranges:
            # 该范围已经保存过y方向范围
            # 取得y方向范围,返回结果
            result = self._values_ranges[last_range]
            # print("3:",last_range,result)
            return adjust_range(result)

        # 该范围没有保存过y方向范围
        # 从macd_data重新计算y方向范围
        macd_list = list(self.macd_data.values())[min_ix:max_ix + 1]
        ndarray = np.array(macd_list) 
        max_price = np.nanmax(ndarray)
        min_price = np.nanmin(ndarray)

        # 取得y方向范围,返回结果
        result = (min_price, max_price)
        self.last_range = last_range
        self._values_ranges[self.last_range] = result
        # print("4:",self.last_range,result)
        return adjust_range(result)


    def get_info_text(self, ix: int) -> str:
        # """"""
        if ix in self.macd_data:
            diff,dea,macd = self.macd_data[ix]
            words = [
                f"diff {diff:.3f}"," ",
                f"dea {dea:.3f}"," ",
                f"macd {macd:.3f}"
                ]
            text = "\n".join(words)
        else:
            text = "diff - \ndea - \nmacd -"

        return text



class NewChartWidget(ChartWidget):
    """"""
    MIN_BAR_COUNT = 100

    def __init__(self, parent: QtWidgets.QWidget = None):
        """"""
        super().__init__(parent)

        self.last_price_line: pg.InfiniteLine = None

    def add_last_price_line(self):
        """"""
        plot = list(self._plots.values())[0]
        color = (255, 255, 255)

        self.last_price_line = pg.InfiniteLine(
            angle=0,
            movable=False,
            label="{value:.1f}",
            pen=pg.mkPen(color, width=1),
            labelOpts={
                "color": color,
                "position": 1,
                "anchors": [(1, 1), (1, 1)]
            }
        )
        self.last_price_line.label.setFont(NORMAL_FONT)
        plot.addItem(self.last_price_line)

    def update_history(self, history: List[BarData]) -> None:
        """
        Update a list of bar data.
        """
        self._manager.update_history(history)

        for item in self._items.values():
            item.update_history(history)

        self._update_plot_limits()

        self.move_to_right()

        self.update_last_price_line(history[-1])

    def update_bar(self, bar: BarData) -> None:
        """
        Update single bar data.
        """
        self._manager.update_bar(bar)

        for item in self._items.values():
            item.update_bar(bar)

        self._update_plot_limits()

        if self._right_ix >= (self._manager.get_count() - self._bar_count / 2):
            self.move_to_right()

        self.update_last_price_line(bar)

    def update_last_price_line(self, bar: BarData) -> None:
        """"""
        if self.last_price_line:
            self.last_price_line.setValue(bar.close_price)


if __name__ == "__main__":
    app = create_qapp()

    # bars = database_manager.load_bar_data(
    #     "IF888",
    #     Exchange.CFFEX,
    #     interval=Interval.MINUTE,
    #     start=datetime(2019, 7, 1),
    #     end=datetime(2019, 7, 17)
    # )

    symbol = "rb2010"
    exchange = Exchange.SHFE
    interval=Interval.MINUTE
    start=datetime(2020, 6, 1)
    end=datetime(2020, 6, 30)    

    dynamic = False  # 是否动态演示
    n = 200          # 缓冲K线根数


    bars = database_manager.load_bar_data(
        symbol=symbol,
        exchange=exchange,
        interval=interval,
        start=start,
        end=end
    )

    widget = NewChartWidget()
    widget.setWindowTitle(f"K线图表——{symbol}.{exchange.value},{interval},{start}-{end}")
    widget.add_plot("candle", hide_x_axis=True)
    widget.add_plot("volume", maximum_height=150)
    widget.add_plot("rsi", maximum_height=150)
    widget.add_plot("macd", maximum_height=150)
    widget.add_item(CandleItem, "candle", "candle")
    widget.add_item(VolumeItem, "volume", "volume")

    widget.add_item(LineItem, "line", "candle")
    widget.add_item(SmaItem, "sma", "candle")
    widget.add_item(RsiItem, "rsi", "rsi")
    widget.add_item(MacdItem, "macd", "macd")
    widget.add_last_price_line()
    widget.add_cursor()

    if dynamic:
        history = bars[:n]      # 先取得最早的n根bar作为历史
        new_data = bars[n:]     # 其它留着演示
    else:
        history = bars[-n:]     # 先取得最新的n根bar作为历史
        new_data = []           # 演示的为空

    widget.update_history(history)

    def update_bar():
        if new_data:
            bar = new_data.pop(0)
            widget.update_bar(bar)

    timer = QtCore.QTimer()
    timer.timeout.connect(update_bar)
    if dynamic:
        timer.start(100)

    widget.show()
    app.exec_()

Traceback (most recent call last):
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnstation\cli.py", line 92, in run_trader
main_engine.add_app(app)
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\trader\engine.py", line 96, in add_app
engine = self.add_engine(app.engine_class)
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\trader\engine.py", line 71, in add_engine
engine = engine_class(self, self.event_engine)
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\app\chart_wizard\engine.py", line 24, in init
rqdata_client.init()
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\trader\rqdata.py", line 62, in init
max_pool_size=1
File "D:\ProgramFiles\VnStudio\lib\site-packages\rqdatac\client.py", line 167, in init
remaining_days = quota["remaining_days"]
TypeError: 'NoneType' object is not subscriptable

我们都知道策略文件中的on_tick(),on_bar()回调函数与K线的合成有关。
N分钟间隔K线是用BarGenerator来合成的,它的构造函数如下:
class BarGenerator:
"""
For:

1. generating 1 minute bar data from tick data
2. generateing x minute bar/x hour bar data from 1 minute data

Notice:
1. for x minute bar, x must be able to divide 60: 2, 3, 5, 6, 10, 15, 20, 30
2. for x hour bar, x can be any number
"""

def __init__(
    self,
    on_bar: Callable,
    window: int = 0,
    on_window_bar: Callable = None,
    interval: Interval = Interval.MINUTE
):

其中window为多少个分钟(假设interval=Interval.MINUTE)合成一根N分钟K线,
on_tick()里调用update_tick(tick),在收到的tick数据的分钟发生变化时,推送合成的
一分钟K线给on_bar():
if not self.bar:
new_minute = True
elif self.bar.datetime.minute != tick.datetime.minute:
self.bar.datetime = self.bar.datetime.replace(
second=0, microsecond=0
)
self.on_bar(self.bar)

        new_minute = True

那让我们看看BarGenerator.on_bar()是怎么判断N分钟K线是否结束的吧:

    # Check if window bar completed
    finished = False

    if self.interval == Interval.MINUTE:
        # x-minute bar
        if not (bar.datetime.minute + 1) % self.window:
            finished = True
    elif self.interval == Interval.HOUR:
        if self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour:
            # 1-hour bar
            if self.window == 1:
                finished = True
            # x-hour bar
            else:
                self.interval_count += 1

                if not self.interval_count % self.window:
                    finished = True
                    self.interval_count = 0

    if finished:
        self.on_window_bar(self.window_bar)
        self.window_bar = None

问题:
它是根据最新一根分钟bar的分钟+1%self.window==0来判断N分钟K线已经结束的。
换句话说:N分钟K线是否结束是已经自然时间来计算的,而不管这中间是否有不规则
的休市时间。当需要合成N分钟价K线如30分钟、60分钟的时候,由于国内期货的交易
时间段在上午10:15~10:30有一个休市时间,这样就会导致同样是30分钟K线,有的交易
时间为30分钟,有的就只有15分钟;同样60分钟K线,有的交易时间为60分钟,有的就
只有45分钟。在分析行情的时,这样可能会有问题的。
建议:
把交易合约的交易时间段考虑进去,在ContractData里增加的合约交易时间段的查询功能,
在BarGenerator中,或在系统设置中增加:K线的间隔为自然时间还是交易时间的设置,
也就是BarGenerator的window参数代表的是自然时间还是交易时间。

问题:
CTA交易今日主界面后,如果已经有持仓,在此界面下想完成平仓,经常会出错。
因为上期所和上期能源的合约在平仓时必须用 “平今”、“平昨”来平仓,而不可以选择 “平” 这个类型,
用户一旦选择了vnpy就崩溃出错。

description

解决建议:
当用户输入完成1,2步设置之后,如果1为SHFE的就,自动更新类型为 【开,平今,平昨】,这样就可以避免vnpy就崩溃出错。

1、当RQData终端用户为标准版本时,RiceQuant只会为终端用户提供分钟和日线K线数据两种类型的数据,
当我们CTA回测功能界面中选择K线周期为1h,w时,界面会报告如下错误:

15:41:40 rb2005.SHFE-1h开始下载历史数据
15:42:02 数据下载失败,触发异常:
Traceback (most recent call last):
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\app\cta_backtester\engine.py", line 381, in run_downloading
data = rqdata_client.query_history(req)
File "D:\ProgramFiles\VnStudio\lib\site-packages\vnpy\trader\rqdata.py", line 136, in query_history
adjust_type="none"
File "D:\ProgramFiles\VnStudio\lib\site-packages\rqdatac\decorators.py", line 131, in wrap
return func(args, **kwargs)
File "D:\ProgramFiles\VnStudio\lib\site-packages\rqdatac\services\get_price.py", line 124, in get_price
pf = get_minbar(order_book_ids, start_date, end_date, fields, duration, market)
File "D:\ProgramFiles\VnStudio\lib\site-packages\rqdatac\services\get_price.py", line 450, in get_minbar
data = [(obid, {k: np.frombuffer(
v) for k, v in d.items()}) for obid, d in data]
TypeError: 'NoneType' object is not iterable

错误估计:当data = rqdata_client.query_history(req)执行后,data中的记录为空时,表头数据不存在导致的后续代码错误,建议增加这种特殊情况的处理代码。软件的品质体现在细节处,vnpy应该能够做到!

2、该界面缺少一个对用户已经下载过合约数据的记录、查询、选择和删除功能,已经下载的合约应该保存到数据库或者文件中,其中应该含有合约代码、合约名称、K线类型、开始和截止时间,以列表的形式显示,这样用户就不会不知道哪个合约下载过,哪个周期有没有下载过了,完全靠记忆操作的话,还要计算机干什么?建议增加一个已经下载过数据的合约信息列表界面。

import pandas as pd
import matplotlib.pyplot as plt
import mpl_finance as mpf

import tushare as ts

dataframe = ts.get_hist_data('510050','2019-06-01','2019-12-23')
fig, ax = plt.subplots(figsize=(6,4))
fig.subplots_adjust(bottom=0.2)
mpf.candlestick2_ohlc(ax,dataframe['open'], dataframe['high'],
dataframe['low'],dataframe['close'], width=0.9,
colorup='r',colordown='g')
ax.autoscale_view()
fig = plt.gcf()

在vnpy 2.0平台上安装tushare,需要进入如VN Studio Prompt,输入如下命令:

pip install tushare
pip install lxml
pip install bs4

然后输入python,进入python 3.7,输入命令:

import tushare as ts

没有返回错误信息,表示安装成功,接着输入

data = ts.get_hist_data('510050','2019-06-01','2019-12-23')

data.head()

返回:

data open high close low volume price_change p_change ma5 ma10 ma20 v_ma5 v_ma10 v_ma20
2019-12-23 3.00 3.02 2.98 2.98 5536351.0 -0.03 -1.00 3.010 2.986 2.963 5168589.60 4952404.80 4466889.50
2019-12-20 3.01 3.03 3.01 3.00 4723815.0 0.00 0.00 3.012 2.981 2.964 5540316.20 4754582.08 4394308.83
2019-12-19 3.02 3.02 3.01 3.01 3793251.0 -0.01 -0.33 3.010 2.974 2.962 5848011.10 4572602.58 4534895.35
2019-12-18 3.02 3.04 3.02 3.02 4853617.5 -0.01 -0.33 2.996 2.965 2.961 5784157.25 4601014.90 4636033.75
2019-12-17 2.99 3.05 3.03 2.99 6935913.5 0.04 1.34 2.982 2.953 2.961 5656477.65 4365869.40 4572117.63

这样获取tushare的股票数据就成功了。

class ArrayManager(object):
def init(self, size=100):
"""Constructor"""
self.count = 0
self.size = size
self.inited = False

    self.open_array = np.zeros(size)
    self.high_array = np.zeros(size)
    self.low_array = np.zeros(size)
    self.close_array = np.zeros(size)
    self.volume_array = np.zeros(size)

在用户策略里经常用 下面的语句来生成一个ArrayManager:

1) self.am = ArrayManager() -----默认最多保存100个周期的bar数据
或者
2) self.am = ArrayManager(200) -----指定最多保存100个周期的bar数据
之后再用户策略的on_bar()或者self.on_xxx_bar()函数中会调用:
self.am.update_bar(bar) ---- 每次执行都会把最老的self.xxx_array一个的数据抛弃,同时添加bar的数据到self.xxx_array[-1]
sma300 = self,am.sma(300) ----- 本人故意用了300
那么问题来了:当一个am中保存的bar数据周期数不足300时,sma300的所有元素都将为NaN:
[NaN,NaN,NaN,.....,NaN]

建议:是否可以把ArrayManager多数据的存在管理做成自适应的?
方法:当用户的策略里对数据的引用数量超过ArrayManager的size时,把size调整为引用数量,重新创建各个数组xxx_array,并且把当前的数据迁移到新数组,这样当用户的bar数据个数达到引用数量时,talib的各个指标就可以计算出有实际意义的返回数组了,就可以适应策略的计算需求。

在CTA策略功能界面中可以加载已经回测好的策略,如图所示:
其中的“初始化”、“启动”、"停止"、“边际”、“移除”按钮的使能与策略的运行状态无关,
可能导致策略被多次加载的问题,可能出重复买卖的情况。这些按钮的状态应该随
策略的运行状态而改变,建议如下:
1.策略未初始化时,“初始化”按钮是有效的,“启动”、"停止"按钮应该是无效的
2.策略已经初始化未启动时,“启动”按钮是有效的,初始化”、"停止"按钮应该是无效的
3.策略已经启动时,初始化”、“启动”按钮是无效的,"停止"按钮应该是有效的
4.“移除”按钮的状态=not(策略已经启动)。

description

VNPY2.0.7版,SimNow的CTP连接,rb2001 开空单10手,TA001开多单1手。然而对多单和空单平仓的时候,出现拒单,信息显示“CTP:平昨仓位不足”,有问题吗?

Traceback (most recent call last):
File "C:\vnstudio\lib\site-packages\vnpy\trader\ui\widget.py", line 858, in send_order
self.main_engine.send_order(req, gateway_name)
File "C:\vnstudio\lib\site-packages\vnpy\app\risk_manager\engine.py", line 58, in send_order
return self._send_order(req, gateway_name)
File "C:\vnstudio\lib\site-packages\vnpy\trader\engine.py", line 173, in send_order
return gateway.send_order(req)
File "C:\vnstudio\lib\site-packages\vnpy\gateway\ctp\ctp_gateway.py", line 174, in send_order
return self.td_api.send_order(req)
File "C:\vnstudio\lib\site-packages\vnpy\gateway\ctp\ctp_gateway.py", line 755, in send_order
self.reqOrderInsert(ctp_req, self.reqid)
ValueError: Cannot convert empty string to a character

新手,初次安装vnpy。我的操作系统是windows10,按照文档里的说明:
1.下载VNStudio (Python 3.7 64位),下载了:vnstudio-2.0.5.exe
2.安装VNStudio,按照目录等都是按照默认的目录

  1. 登陆www.simnow.com.cn,注册了防真用户,并且事后修改了用户密码(据说不修改无法连接和交易)
  2. 从菜单启动vnstation
  3. 启动VN Trader Lite,使用SimNow注册的
    户名称:xxxxxx(我的账号)
    密码:xxxxxx(我的秘密)
    经纪商代码:9999
    交易服务器:tcp://180.168.146.187:10101
    行情服务器:tcp://180.168.146.187:10111
    其他未填写

连接后,日志窗口显示行情服务器连接成功,但没有显示交易服务器连接成功。
6、连接后仍然没有行情数据,主动查询也没有行情数据显示

问题:
是否我安装的过程缺少了?是否还要安装类似MongoDB、Wing IDE、VS2013 Community版本之类的软件?

本人是初次接触vn.py,首次安装,我是windows10用户。
选择下载VNStudio (Python 3.7 64位) ,
VNStudio是vn.py团队自行打包的一键安装版本,整合了:
• Python 3.7(社区官方版本)
• vn.py框架和其他相关库
• VN Station量化工作站(vn.py框架的图形化管理工具)

运行了vnstudio-2.0.5.exe,安装完成。从系统菜单选择vnstation,运行
vn trader lite,接下来设置连接:
• 用户名username:我的simnow账户
• 密码password:我的simnow密码
• 经纪商编号brokerid:9999 (SimNow默认经纪商编号)
• 交易服务器地址td_address:180.168.146.187:10000
• 行情服务器地址md_address:180.168.146.187:10011

问题:为什么的看不到任何行情数据?

跪求高手指点!

© 2015-2022 微信 18391752892
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】