pythonnet을 사용하여 python 리스너에서 .NET 이벤트를 구독하는 방법은 무엇입니까?

Nov 15 2020

Python을 사용하여 FX 거래 응용 프로그램에서 (가격) 이벤트 를 구독하는 이벤트 리스너를 만들려고합니다 . 원래 애플리케이션은 MetaTrader4 라는 기본 32 비트 Windows 앱 입니다. 여기에는 API가 없으므로 mtapi 브리지는 다른 프로그래밍 언어와 상호 작용할 수 있도록 .NET으로 설계되었습니다. 응용 프로그램에는 몇 가지 이벤트가 정의되어 있으며 그 중 두 가지는 다음 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

최신 정보

참고로 속성, 유형 및 다음과 같은 관련 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 % 이상을 살펴 보았지만 사용 사례별로 적용 가능성에 거의 성공하지 못했습니다. 그중 일부는 다음과 같습니다.

  • Python 클래스는 다른 언어와 같은 이벤트를 지원합니까?
  • 이 이벤트 처리기 등록을 C #에서 VB.net으로 변환하는 올바른 방법은 무엇입니까?
  • VB 델리게이트를 파이썬 이벤트 핸들러로 어떻게 변환합니까?
  • 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/

답변

3 not2qubit Nov 23 2020 at 21:56

며칠 그리고 오랜 시간 후에 나는 여러 가지 실수를 발견했습니다. 항상 그렇듯이 2-3 개의 간단한 실수를 조합하면 오랫동안 당신의 삶을 비참하게 만들 수 있습니다. 그러나 가장 큰 실수는 listner (일명 delegate )가 많은 기능 __init__과 함께 복잡 해야한다고 생각하는 것입니다 __iadd__. 잘못된! Python.NET은 대부분의 경우에만 작동하지만 작은 실수를하더라도 발생하는 오류는 거의 쓸모가 없습니다.

원래 코드에는 1.5 개의 문제가 있습니다.

  • 두 가지 다른 견적 기능 이 있습니다 .

  • 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
1 LOST Nov 20 2020 at 05:24

링크 한 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