【问题标题】:How to subscribe to a .NET event in a python listener using pythonnet?如何使用 pythonnet 在 python 侦听器中订阅 .NET 事件?
【发布时间】:2020-11-15 18:41:27
【问题描述】:

我正在尝试使用 Python 创建一个事件侦听器来订阅来自外汇交易应用程序的 tick(价格)事件。原始应用程序是一个名为 MetaTrader4 的原生 32 位 Windows 应用程序。它没有任何 API,因此在 .NET 中设计了 mtapi 桥以允许其他编程语言与之交互。该应用程序定义了一些事件,其中两个是:QuoteUpdateQuoteUpdated

所以我想使用python.net 编写一个监听器(delegate?)来订阅这个事件。但由于我无法理解 .NET 代码是如何产生这些事件的,也无法理解如何正确使用 pythonnet,所以我无法让它工作。我也一直遇到错误:

TypeError: 'EventBinding' object is not callable

除了this“FIXME”评论之外,谷歌搜索不会返回任何有用的信息。

这是我的代码:

import os, sys, clr
sys.path.append(r"C:\Program Files\MtApi")
asm = clr.AddReference('MtApi')
import MtApi as mt

res = 0

def printTick(symbol, ask, bid):
    print('Tick: Symbol: {}  Ask: {:.5f}  Bid: {:.5f}'.format(symbol, ask, bid))

# Setup .NET API bridge connection
mtc = mt.MtApiClient()
res = mtc.BeginConnect('127.0.0.1', 8222);

#--------------------------------------
# Register and use the listener
#--------------------------------------
# This does NOT work!
mtc.QuoteUpdate += printTick

#...

我的代码的意图应该很清楚。

问:如何在接收到QuoteUpdate .NET 事件时让监听器触发?


供参考:

...
private void _client_QuoteUpdated(MTApiService.MtQuote quote) { 
    if (quote != null) { 
        QuoteUpdate?.Invoke(this, new MtQuoteEventArgs(new MtQuote(quote))); 
        QuoteUpdated?.Invoke(this, quote.Instrument, quote.Bid, quote.Ask); 
    } 
} 
...
public event MtApiQuoteHandler QuoteUpdated; 
public event EventHandler<MtQuoteEventArgs> QuoteUpdate; 
public event EventHandler<MtQuoteEventArgs> QuoteAdded; 
public event EventHandler<MtQuoteEventArgs> QuoteRemoved; 
Imports MtApi
Public Class Form1
    Private apiClient As MtApiClient
    Public Sub New()
        InitializeComponent()
        apiClient = New MtApiClient
        AddHandler apiClient.QuoteUpdated, AddressOf QuoteUpdatedHandler
    End Sub

    Sub QuoteUpdatedHandler(sender As Object, symbol As String, bid As Double, ask As Double)
        Dim quoteSrt As String
        quoteSrt = symbol + ": Bid = " + bid.ToString() + "; Ask = " + ask.ToString()
        ListBoxQuotesUpdate.Invoke(Sub()
                                       ListBoxQuotesUpdate.Items.Add(quoteSrt)
                                   End Sub)
        Console.WriteLine(quoteSrt)
    End Sub
    Private Sub btnConnect_Click(sender As System.Object, e As System.EventArgs) Handles btnConnect.Click
        apiClient.BeginConnect(8222)
    End Sub
    Private Sub btnDisconnect_Click(sender As System.Object, e As System.EventArgs) Handles btnDisconnect.Click
        apiClient.BeginDisconnect()
    End Sub
End Class

更新

作为参考,我们有以下相关的 DLL 调用,由 attributes, types__doc__ 给出:

attr: QuoteAdded             type: <class 'CLR.EventBinding'>    doc: <n/a>
attr: QuoteRemoved           type: <class 'CLR.EventBinding'>    doc: <n/a>
attr: QuoteUpdate            type: <class 'CLR.EventBinding'>    doc: <n/a>
attr: QuoteUpdated           type: <class 'CLR.EventBinding'>    doc: <n/a>

attr: add_QuoteAdded         type: <class 'CLR.MethodBinding'>   doc: Void add_QuoteAdded(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: add_QuoteRemoved       type: <class 'CLR.MethodBinding'>   doc: Void add_QuoteRemoved(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: add_QuoteUpdate        type: <class 'CLR.MethodBinding'>   doc: Void add_QuoteUpdate(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: add_QuoteUpdated       type: <class 'CLR.MethodBinding'>   doc: Void add_QuoteUpdated(MtApi.MtApiQuoteHandler)

attr: remove_QuoteAdded      type: <class 'CLR.MethodBinding'>   doc: Void remove_QuoteAdded(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: remove_QuoteRemoved    type: <class 'CLR.MethodBinding'>   doc: Void remove_QuoteRemoved(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: remove_QuoteUpdate     type: <class 'CLR.MethodBinding'>   doc: Void remove_QuoteUpdate(System.EventHandler`1[MtApi.MtQuoteEventArgs])
attr: remove_QuoteUpdated    type: <class 'CLR.MethodBinding'>   doc: Void remove_QuoteUpdated(MtApi.MtApiQuoteHandler)


类似问题:

实际上有 100 多个相关的 SO 问题,我可能已经查看了超过 60% 的问题,但对用例的适用性几乎为零。其中一些是:

【问题讨论】:

  • 查看此链接:pythonnet.github.io,代表和活动部分。很明显,你需要将 python 方法包装到委托中,然后将其添加到事件中
  • 嗨 Quercus,是的,我已经看过了,但没有帮助。
  • 您尝试过:mtc.QuoteUpdate += printTick 吗?根据文档,它应该可以工作(但是参数会不正确-但至少应该触发)
  • 是的,我认为我遇到的主要问题是知道将mtc.QuoteUpdate 部分放在哪里。那是连接器……我想。仅供参考。\,我完全不知道我是否正确构建了该类。我是从第一个 SO 链接中得到的。

标签: python c# .net event-handling python.net


【解决方案1】:

经过几天和几个小时后,我发现了一些错误。与往常一样,2-3 个简单错误的组合会使您的生活长期痛苦。但最大的错误是被愚弄了,认为侦听器(又名。delegate)必须使用一堆__init____iadd__ 函数来复杂化。错误的! Python.NET 大部分时间都可以正常工作,但如果你犯了任何小错误,那么你得到的错误(如果有的话)将毫无用处。

我原来的代码有1.5个问题。

  • 有2个不同的引用函数,分别是:

  • QuoteUpdate 返回 sender 和一个在 .NET 中名为“MtQuoteEventArgs”的对象

  • QuoteUpdated 返回 sender 和 3 个参数

  • 因此我们需要修复 printTick() 函数和监听器线路。

更正后的代码是:

def printTick(source, symbol, ask, bid):
    print('Tick: Symbol: {}  Ask: {:.5f}  Bid: {:.5f}'.format(symbol, ask, bid))

...

mtc.QuoteUpdates += printTick

有关 C# 事件和委托的更多信息:

【讨论】:

    【解决方案2】:

    根据您链接的 mtapi 文档,代码应该是:

    def printTick(sender, args):
      print(str(args.Quote.Instrument))
    
    
    mtc = mt.MtApiClient()
    res = mtc.BeginConnect('127.0.0.1', 8222)
    
    mtc.QuoteUpdate += printTick  # Subscribe & handle new repeated events
    
    rA  = mtc.SymbolInfoTick(SYM) # Make a request to get a one-time tick data
    
    # Need wait loop here
    

    【讨论】:

    • 很遗憾现在没有市场数据,所以无法正常测试。但是连接顺序是错误的。我还更新了 OP 添加了可用方法并删除了 rA 行,因为它在这里没有用。不确定Quote.Instrument 部分是否正确,但也许。
    • 这些监听器应该如何工作。我的意思是,我需要将代码放入循环中并等待它接收通知,还是应该停止执行,直到触发事件? (即我的代码在mtc... += printTick 语句之后应该做什么?)
    • @not2qubit 我只熟悉 Python.NET,不熟悉 MtApi+= printTick 应该满足您的需求:订阅 .NET 事件。
    猜你喜欢
    • 2018-12-12
    • 2016-04-12
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多