如何使用 pythonnet 在 python 侦听器中订阅 .NET 事件?
How to subscribe to a .NET event in a python listener using pythonnet?
我正在尝试使用 Python 让事件侦听器订阅来自外汇交易应用程序的 tick(价格)事件。原始应用程序是名为 MetaTrader4 的本机 32 位 Windows 应用程序。这没有任何 API,因此 mtapi 桥已在 .NET 中设计,以允许其他编程语言与其交互。该应用程序定义了一些事件,其中两个是:QuoteUpdate
和 QuoteUpdated
.
所以我想写一个监听器(委托?)使用python.net来订阅这个事件。但是由于我无法理解 .NET 代码是如何产生这些事件的,也无法理解如何正确使用 pythonnet,所以我无法让它发挥作用。我也把运行存入错误:
TypeError: 'EventBinding' object is not callable
谷歌搜索 return 除了 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 事件时触发?
供参考:
- C# 中的 .NET 代码(来自 MtApiClient.cs 如下所示:
...
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;
- 还有一个小 VB Test app 看起来像这样:
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 调用,由 属性、类型 和 __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% 以上,但对用例的适用性几乎为零。其中一些是:
- Does Python classes support events like other languages?
- https://ironpython.net/documentation/dotnet/dotnet.html(也可能是相关的)
- https://openbookproject.net/thinkcs/python/english3e/events.html
- https://code.activestate.com/recipes/410686-c-style-events-in-python/
根据您链接的 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
经过几天和几个小时后,我发现了一系列错误。与往常一样,2-3 个简单错误的组合可能会让您的生活很长一段时间都痛苦不堪。但最大的错误是被愚弄认为监听器(又名。delegate)必须由一堆 __init__
和 __iadd__
函数复杂化.错误的! Python.NET 大多数时候都能正常工作,但如果你犯了任何小错误,你得到的错误(如果有的话)是非常无用的。
我的原始代码有 1.5 个问题。
有 2 个不同的 Quote 函数,即:
QuoteUpdate
其中 returns sender 和一个名为“MtQuoteEventArgs”的 object .NET
QuoteUpdated
其中 returns sender 和 3 arguments.
因此我们需要修复 printTick() 函数和侦听器行。
更正后的代码是:
def printTick(source, symbol, ask, bid):
print('Tick: Symbol: {} Ask: {:.5f} Bid: {:.5f}'.format(symbol, ask, bid))
...
mtc.QuoteUpdates += printTick
有关 C# 的更多信息事件和委托:
我正在尝试使用 Python 让事件侦听器订阅来自外汇交易应用程序的 tick(价格)事件。原始应用程序是名为 MetaTrader4 的本机 32 位 Windows 应用程序。这没有任何 API,因此 mtapi 桥已在 .NET 中设计,以允许其他编程语言与其交互。该应用程序定义了一些事件,其中两个是:QuoteUpdate
和 QuoteUpdated
.
所以我想写一个监听器(委托?)使用python.net来订阅这个事件。但是由于我无法理解 .NET 代码是如何产生这些事件的,也无法理解如何正确使用 pythonnet,所以我无法让它发挥作用。我也把运行存入错误:
TypeError: 'EventBinding' object is not callable
谷歌搜索 return 除了 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 事件时触发?
供参考:
- C# 中的 .NET 代码(来自 MtApiClient.cs 如下所示:
...
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;
- 还有一个小 VB Test app 看起来像这样:
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 调用,由 属性、类型 和 __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% 以上,但对用例的适用性几乎为零。其中一些是:
- Does Python classes support events like other languages?
- https://ironpython.net/documentation/dotnet/dotnet.html(也可能是相关的)
- https://openbookproject.net/thinkcs/python/english3e/events.html
- https://code.activestate.com/recipes/410686-c-style-events-in-python/
根据您链接的 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
经过几天和几个小时后,我发现了一系列错误。与往常一样,2-3 个简单错误的组合可能会让您的生活很长一段时间都痛苦不堪。但最大的错误是被愚弄认为监听器(又名。delegate)必须由一堆 __init__
和 __iadd__
函数复杂化.错误的! Python.NET 大多数时候都能正常工作,但如果你犯了任何小错误,你得到的错误(如果有的话)是非常无用的。
我的原始代码有 1.5 个问题。
有 2 个不同的 Quote 函数,即:
QuoteUpdate
其中 returns sender 和一个名为“MtQuoteEventArgs”的 object .NETQuoteUpdated
其中 returns sender 和 3 arguments.因此我们需要修复 printTick() 函数和侦听器行。
更正后的代码是:
def printTick(source, symbol, ask, bid):
print('Tick: Symbol: {} Ask: {:.5f} Bid: {:.5f}'.format(symbol, ask, bid))
...
mtc.QuoteUpdates += printTick
有关 C# 的更多信息事件和委托: