Pythonnetを使用してPythonリスナーで.NETイベントをサブスクライブする方法は?
Pythonを使用して、FX取引アプリケーションからティック(価格)イベントをサブスクライブするイベントリスナーを作成しようとしています。元のアプリケーションは、MetaTrader4と呼ばれるネイティブの32ビットWindowsアプリです。これにはAPIがないため、mtapiブリッジは他のプログラミング言語が相互作用できるように.NETで設計されています。アプリケーションにはいくつかのイベントが定義されており、そのうちの2つは:QuoteUpdateとQuoteUpdatedです。
そこで、python.netを使用してこのイベントをサブスクライブするリスナー(デリゲート?)を作成したいと思います。しかし、.NETコードがこれらのイベントをどのように生成しているか、またpythonnetを適切に使用する方法も理解できないため、これを機能させることができませんでした。私もエラーに遭遇し続けます:
TypeError: 'EventBinding' object is not callable
これをグーグルで検索しても、この「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
#...
私のコードの意図は明確でなければなりません。
Q: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テストアプリは次のようになります。
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
更新
参考までに、属性、タイプ、および__doc__:によって指定された次の関連するDLL呼び出しがあります。
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)
同様の問題:
文字通り何百もの関連するSOの問題があり、おそらくそれらの60%以上を調べましたが、ユースケースによる適用性の成功はほぼゼロです。そのうちのいくつかは:
- Pythonクラスは他の言語のようなイベントをサポートしていますか?
- このイベントハンドラー登録をC#からVB.netに変換する正しい方法は何ですか?
- VBデリゲートをPythonイベントハンドラーに変換するにはどうすればよいですか?
- 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/
回答
数日と数時間後、私は間違いの組み合わせを見つけました。いつものように、2〜3の単純な間違いの組み合わせは、あなたの人生を長い間悲惨にする可能性があります。しかし、すべての最大の過ちは、LISTNER(別名。と思うようにだまされていたデリゲートが)の束を合併しなければならなかった__init__と__iadd__機能。違う!Python.NETはほとんどの場合機能しますが、小さな間違いをした場合に発生するエラー(あるとしても)はほとんど役に立ちません。
私の元のコードには1.5の問題があります。
2つの異なる見積もり関数がありました。
QuoteUpdate.NETで送信者と「MtQuoteEventArgs」という名前のオブジェクトを返しますQuoteUpdated送信者と3つの引数を返します。したがって、printTick()関数とリスナー行の両方を修正する必要があります。
修正されたコードは次のとおりです。
def printTick(source, symbol, ask, bid):
print('Tick: Symbol: {} Ask: {:.5f} Bid: {:.5f}'.format(symbol, ask, bid))
...
mtc.QuoteUpdates += printTick
C#イベントとデリゲートに関する追加情報:
- https://www.tutorialsteacher.com/csharp/csharp-event
リンクした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