วิธีสมัครรับเหตุการณ์. NET ใน python listener โดยใช้ pythonnet
ฉันกำลังพยายามทำให้ผู้ฟังเหตุการณ์สมัครเป็นสมาชิกเหตุการณ์เห็บ (ราคา) จากแอปพลิเคชันการซื้อขาย FX โดยใช้ Python แอพลิเคชันเดิมเป็น 32 บิตของ Windows แอพพลิเคพื้นเมืองที่เรียกว่าโปรแกรม MetaTrader4 สิ่งนี้ไม่มี API ใด ๆ ดังนั้นmtapi bridge จึงได้รับการออกแบบใน. NET เพื่อให้ภาษาโปรแกรมอื่น ๆ สามารถโต้ตอบกับมันได้ แอปพลิเคชันมีการกำหนดเหตุการณ์บางอย่างซึ่งสองเหตุการณ์คือ: QuoteUpdateและQuoteUpdated.
ดังนั้นฉันจึงต้องการเขียนผู้ฟัง ( delegate ?) โดยใช้python.netเพื่อสมัครเข้าร่วมกิจกรรมนี้ แต่เนื่องจากฉันไม่สามารถเข้าใจว่าโค้ด. NET สร้างเหตุการณ์เหล่านี้ได้อย่างไรและไม่สามารถใช้pythonnetอย่างถูกต้องได้อย่างไรฉันจึงไม่สามารถทำให้สิ่งนี้ทำงานได้ ฉันยังคงพบข้อผิดพลาด:
TypeError: 'EventBinding' object is not callable
Googling นี้ไม่ได้กลับมาอะไรที่เป็นประโยชน์นอกเหนือนี้ "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
สำหรับการอ้างอิง:
- รหัส. NET ใน C # (จาก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ขนาดเล็กมีลักษณะดังนี้:
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)
ปัญหาที่คล้ายกัน:
มีปัญหา SO ที่เกี่ยวข้องอย่างแท้จริง 100 รายการและฉันอาจดูมากกว่า 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 (aka. delegate ) ต้องซับซ้อนกับกลุ่ม__init__และ__iadd__ฟังก์ชันมากมาย ไม่ถูกต้อง! Python.NET ใช้งานได้เกือบตลอดเวลา แต่ข้อผิดพลาดที่คุณได้รับ (ถ้ามี) นั้นค่อนข้างไร้ประโยชน์หากคุณทำผิดพลาดเล็กน้อย
มีปัญหา 1.5 กับรหัสเดิมของฉัน
มีฟังก์ชั่นใบเสนอราคา 2 แบบ ได้แก่ :
QuoteUpdateซึ่งส่งคืนผู้ส่งและวัตถุชื่อ "MtQuoteEventArgs" ใน. NETQuoteUpdatedซึ่งผลตอบแทนที่ผู้ส่งและ 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