Làm cách nào để đăng ký sự kiện .NET trong trình nghe python bằng pythonnet?

Nov 15 2020

Tôi đang cố gắng làm cho một người nghe sự kiện đăng ký một sự kiện đánh dấu (giá) từ một ứng dụng giao dịch FX bằng Python. Ứng dụng gốc là một ứng dụng Windows 32 bit gốc có tên là MetaTrader4 . Điều này không có bất kỳ API nào, vì vậy mtapi bridge đã được thiết kế trong .NET để cho phép các ngôn ngữ lập trình khác tương tác với nó. Ứng dụng có một số sự kiện được xác định, hai trong số đó là: QuoteUpdateQuoteUpdated.

Vì vậy, tôi muốn viết một trình nghe ( đại biểu ?) Bằng cách sử dụng python.net để đăng ký sự kiện này. Nhưng vì tôi không thể hiểu cách mã .NET tạo ra các sự kiện này và cũng không phải cách sử dụng pythonnet đúng cách , tôi không thể làm cho điều này hoạt động. Tôi cũng tiếp tục gặp lỗi:

TypeError: 'EventBinding' object is not callable

Googling này không trả lại bất cứ điều gì hữu ích, ngoài này "FIXME" nhận xét.

Đây là mã của tôi:

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

#...

Ý định cho mã của tôi phải rõ ràng.

H: Làm cách nào để tôi có thể kích hoạt trình nghe của mình khi nhận được QuoteUpdatesự kiện .NET?


Để tham khảo:

  • Mã .NET trong C # (từ MtApiClient.cs trông như thế này:
...
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; 
  • Và một ứng dụng VB Test nhỏ trông như thế này:
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

CẬP NHẬT

Để tham khảo, chúng tôi có các lệnh gọi DLL có liên quan sau, được cung cấp bởi các thuộc tính, loại__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)


Các vấn đề tương tự:

Thực sự có 100 vấn đề SO liên quan, và có lẽ tôi đã xem xét hơn 60% trong số đó nhưng gần như không có thành công về khả năng áp dụng cho từng trường hợp sử dụng. Một số trong số đó là:

  • Các lớp Python có hỗ trợ các sự kiện như các ngôn ngữ khác không?
  • Cách chính xác để chuyển đổi đăng ký trình xử lý sự kiện này từ C # sang VB.net là gì?
  • Làm cách nào để chuyển đổi một đại biểu VB thành một trình xử lý sự kiện python?
  • https://ironpython.net/documentation/dotnet/dotnet.html (cũng có thể có liên quan)
  • https://openbookproject.net/thinkcs/python/english3e/events.html
  • https://code.activestate.com/recipes/410686-c-style-events-in-python/

Trả lời

3 not2qubit Nov 23 2020 at 21:56

Sau một vài ngày và một số giờ dài, tôi đã tìm thấy một (các) sai lầm. Như mọi khi, sự kết hợp của 2-3 sai lầm đơn giản có thể khiến cuộc sống của bạn khốn khổ trong một thời gian dài. Nhưng sai lầm lớn nhất của tất cả, đã bị lừa khi nghĩ rằng một listner (aka. Đại biểu ) đã phải trở nên phức tạp với một loạt các __init____iadd__các chức năng. Sai lầm! Python.NET chỉ hoạt động hầu hết thời gian nhưng các lỗi bạn gặp phải (nếu có) khá vô ích nếu bạn mắc phải bất kỳ lỗi nhỏ nào.

Có 1,5 vấn đề với mã gốc của tôi.

  • Có 2 chức năng Trích dẫn khác nhau , đó là:

  • QuoteUpdatetrả về người gửi và một đối tượng có tên "MtQuoteEventArgs" trong .NET

  • QuoteUpdatedtrả về người gửi và 3 đối số .

  • Do đó chúng ta cần sửa cả hàm printTick () và dòng lắng nghe.

Mã đã sửa là:

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

...

mtc.QuoteUpdates += printTick

Để biết thêm thông tin về các sự kiện và đại biểu C # :

  • https://www.tutorialsteacher.com/csharp/csharp-event
1 LOST Nov 20 2020 at 05:24

Theo tài liệu mtapi bạn đã liên kết, mã phải là:

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