VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 93
声望: 14

用python编写指标和以往熟悉的文华,博弈大师等有很大的区别,你写的代码最终在图形上是什么样子,看一看才能心安。

于是有了下面这段代码:

from datetime import datetime
from typing import  Dict
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.database import database_manager
from vnpy.app.cta_strategy import ArrayManager
from vnpy.chart import ChartWidget, VolumeItem, CandleItem
import pyqtgraph as pg
from vnpy.trader.ui import create_qapp, QtCore, QtGui
from vnpy.trader.object import BarData
from vnpy.chart.manager import BarManager


class ZB(CandleItem):
    """自定义指标显示"""

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

        self.blue_pen: QtGui.QPen = pg.mkPen(color=(100, 100, 255), width=2)
        self.sma_data: Dict[int, float] = {}

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

        if not self.sma_data:
            bars = self._manager.get_all_bars()
            sma_array = [bar.down_line for bar in bars]

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

        if ix in self.sma_data:
            return self.sma_data[ix]

        sma_value = sma_array[-1]

        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"ZB {sma_value:.2f}"
        else:
            text = "ZB -"

        return text

class ZB2(CandleItem):
    """自定义指标显示"""

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

        self.blue_pen: QtGui.QPen = pg.mkPen(color=(100, 100, 255), width=2)
        self.sma_data: Dict[int, float] = {}

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

        if not self.sma_data:
            bars = self._manager.get_all_bars()
            sma_array = [bar.up_line for bar in bars]

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

        if ix in self.sma_data:
            return self.sma_data[ix]

        sma_value = sma_array[-1]

        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"ZB {sma_value:.2f}"
        else:
            text = "ZB -"

        return text


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

    symbol = "CL-20210322-USD-FUT"
    exchange = Exchange.NYMEX
    interval = Interval.MINUTE_30
    start = datetime(2021, 1, 1)
    end = datetime(2022, 1, 1)

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

    am = ArrayManager(50)
    new_data = bars[:]
    line_up = []
    line_down = []

    while new_data :
        bar = new_data.pop(0)
        am.update_bar(bar)
        up, down = am.boll(20,2)
        line_up.append(up)
        line_down.append(down)   #这里调用合适的公式就好了

    print("K线数量是", len(bars), "指标数据是", len(line_up))

    i = 0
    while line_down :
        bars[i].down_line = line_down.pop(0)
        bars[i].up_line = line_up.pop(0)
        i = i + 1
    print("共处理了", i, "数据")

    widget = ChartWidget()
    widget.add_plot("candle", hide_x_axis=True)
    widget.add_plot("volume", maximum_height=250)
    widget.add_item(CandleItem, "candle", "candle")
    widget.add_item(VolumeItem, "volume", "volume")

    widget.add_item(ZB, "ZB", "candle")
    widget.add_item(ZB2, "ZB2", "candle")
    widget.add_cursor()

    history = bars
    widget.update_history(history)

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

    timer = QtCore.QTimer()
    timer.timeout.connect(update_bar)

    widget.show()
    app.exec_()

因为我使用的盈透可以随时下载各种周期的历史数据,所以我只要下载然后存在数据库中。直接用代码读取就可以看见最新的k线。
如果你需要下载盈透的数据,可以参考我的上一个帖子。
https://www.vnpy.com/forum/topic/6123-ying-tou-jie-kou-xia-zai-5fen-zhong-xian-bing-xian-shi-tu-biao?page=1#pid21676

其他的接口我不熟。

Member
avatar
加入于:
帖子: 93
声望: 14

下面我简单说明一下:


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

    symbol = "CL-20210322-USD-FUT"
    exchange = Exchange.NYMEX
    interval = Interval.MINUTE_30
    start = datetime(2021, 1, 1)
    end = datetime(2022, 1, 1)

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

这一段从数据库读取数据,需要说明的是 interval = Interval.MINUTE_30
MINUTE_30是我自己定义的,详情请看上面的帖子。

Member
avatar
加入于:
帖子: 93
声望: 14

下面的就是关键了


    am = ArrayManager(50)      #引入了ArrayManager,我们的指标都是写在这里的,直接调用,你写的什么样就显示什么。
    new_data = bars[:]            #$一份数据备用
    line_up = []             #定义了两个空的数组
    line_down = []

    while new_data :
        bar = new_data.pop(0)
        am.update_bar(bar)            #把数据一个一个推到am里,
        up, down = am.boll(20,2)     #这里调用合适的公式就好了,你写的公式也在这里调用
        line_up.append(up)
        line_down.append(down)   # 把得到的两个返回值存在临时数组中

    print("K线数量是", len(bars), "指标数据是", len(line_up))

    i = 0
    while line_down :
        bars[i].down_line = line_down.pop(0)       #把bar增加了数据结构,原来是$高低$,现在新增了上通道和下通道
        bars[i].up_line = line_up.pop(0)        #然后把刚才的数据存进去。
        i = i + 1
    print("共$了", i, "数据")

这里的关键是调用ArrayManager得到的结果怎么传递给绘图功能。后来我发现系统会把bar数据推给绘图对象,
于是我就把计算得到的指标值加到bar里面。

Member
avatar
加入于:
帖子: 93
声望: 14

关于绘图,是使用原来的sma改的,里面的代码我都没有动。只是改了def get_sma_value函数。


class ZB(CandleItem):
    """自定义指标显示"""

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

        self.blue_pen: QtGui.QPen = pg.mkPen(color=(100, 100, 255), width=2)
        self.sma_data: Dict[int, float] = {}

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

        if not self.sma_data:
            bars = self._manager.get_all_bars()
            sma_array = [bar.down_line for bar in bars]   #刚才存在bar里的数据down_line,直接读出来就可以了。

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

        if ix in self.sma_data:
            return self.sma_data[ix]

        sma_value = sma_array[-1]

        return sma_value

当然,这样只画了一条线,于是把代码copy一份,从起个名字,第二条线就有了,只是调用的时候up_line了。

Member
avatar
加入于:
帖子: 93
声望: 14

这里几乎不需要解释了,


    widget = ChartWidget()
    widget.add_plot("candle", hide_x_axis=True)
    widget.add_plot("volume", maximum_height=250)
    widget.add_item(CandleItem, "candle", "candle")
    widget.add_item(VolumeItem, "volume", "volume")

    widget.add_item(ZB, "ZB", "candle")      #把两条线放在图上就好了。
    widget.add_item(ZB2, "ZB2", "candle")
    widget.add_cursor()
Member
avatar
加入于:
帖子: 93
声望: 14

description

最后的结果是这个,调用的是系统的布林通道。使用的是30分钟数据。

用这个方法,你可以把任何指标显示在当前的图表上,只需要稍微改一下代码。
如果你只有一分钟数据,就只能显示在一分钟上,我的盈透接口有所有周期的数据。所以我没有写 $$数据的部分。需要的话你可以自己加上。

Administrator
avatar
加入于:
帖子: 4502
声望: 321

给你加个精华

Member
avatar
加入于:
帖子: 12
声望: 0

黄裳 wrote:

最后的结果是这个,调用的是系统的布林通道。使用的是30分钟数据。

用这个方法,你可以把任何指标显示在当前的图表上,只需要稍微改一下代码。
如果你只有一分钟数据,就只能显示在一分钟上,我的盈透接口有所有周期的数据。所以我没有写 $$数据的部分。需要的话你可以自己加上。
多谢楼主,复制下来直接就能画图
黄裳 wrote:

最后的结果是这个,调用的是系统的布林通道。使用的是30分钟数据。

用这个方法,你可以把任何指标显示在当前的图表上,只需要稍微改一下代码。
如果你只有一分钟数据,就只能显示在一分钟上,我的盈透接口有所有周期的数据。所以我没有写 $$数据的部分。需要的话你可以自己加上。

多谢楼主,复制下来直接就能用

Member
avatar
加入于:
帖子: 7
声望: 1

多谢楼主,这样用起来顺手多了。

Member
avatar
加入于:
帖子: 7
声望: 1

太棒了,正好需要这么一个东西来直观的显示策略形态。

Member
avatar
加入于:
帖子: 7
声望: 1

不过话说TradingView也能很方便的验证一些思路。

Member
avatar
加入于:
帖子: 23
声望: 0

感谢大佬,这个正是我需要的。

Member
avatar
加入于:
帖子: 4
声望: 0

感谢大佬,正好有这方面的需求

Member
avatar
加入于:
帖子: 1
声望: 0

mark 回头仔细看

Member
加入于:
帖子: 60
声望: 8

这个图表会不会随着最新行情数据更新而更新?

Member
avatar
加入于:
帖子: 3
声望: 0

正是我需要的

Member
avatar
加入于:
帖子: 3
声望: 0

这个文件是创建到哪里,改那个文件啊,研究半天没搞懂,有人愿意一起交流吗

Member
avatar
加入于:
帖子: 11
声望: 2

金冶不喝酒 wrote:

这个文件是创建到哪里,改那个文件啊,研究半天没搞懂,有人愿意一起交流吗
```
from datetime import datetime
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.database import get_database
from vnpy.trader.object import BarData, TickData
from typing import Dict, List
from vnpy_ctastrategy import ArrayManager
from vnpy.chart import ChartWidget, VolumeItem, CandleItem
import pyqtgraph as pg
from vnpy.trader.ui import create_qapp, QtCore, QtGui
from vnpy.chart.manager import BarManager

if name == "main":
app = create_qapp()

# 获取数据服务实例
database = get_database()

symbol: str = "i2205-C-700"
exchange = Exchange.DCE
interval = Interval.DAILY
start = datetime(2021, 1, 1)
end = datetime(2022, 1, 1)

#获取k线历史数据
bars = database.load_bar_data(
    symbol=symbol,
    exchange=exchange,
    start=start,
    end=end,
    interval=interval
)

```
改抬头的import,后面取数的一部分

Member
avatar
加入于:
帖子: 1
声望: 0

fudingyu wrote:

不过话说TradingView也能很方便的验证一些思路。

同意这个观点。

TradingView视觉太赞了,没有之一。

vnpy做参数优化比较友好一些。

Member
avatar
加入于:
帖子: 6
声望: 0

磨剑 wrote:

金冶不喝酒 wrote:

这个文件是创建到哪里,改那个文件啊,研究半天没搞懂,有人愿意一起交流吗
```
from datetime import datetime
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.database import get_database
from vnpy.trader.object import BarData, TickData
from typing import Dict, List
from vnpy_ctastrategy import ArrayManager
from vnpy.chart import ChartWidget, VolumeItem, CandleItem
import pyqtgraph as pg
from vnpy.trader.ui import create_qapp, QtCore, QtGui
from vnpy.chart.manager import BarManager

if name == "main":
app = create_qapp()

# 获取数据服务实例
database = get_database()

symbol: str = "i2205-C-700"
exchange = Exchange.DCE
interval = Interval.DAILY
start = datetime(2021, 1, 1)
end = datetime(2022, 1, 1)

#获取k线历史数据
bars = database.load_bar_data(
    symbol=symbol,
    exchange=exchange,
    start=start,
    end=end,
    interval=interval
)

```
改抬头的import,后面取数的一部分

大佬,请问是在VNPY的哪个文件做修改?

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

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