mit Variablen innerhalb der Klasse arbeiten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Hallo,

folgendes Script hab ich erstellt:

Code: Alles auswählen

def exp(stock):
    from ibapi.client import EClient
    from ibapi.wrapper import EWrapper
    from ibapi.common import SetOfString
    from ibapi.common import SetOfFloat
    from ibapi.contract import Contract
    from threading import Timer
    from datetime import datetime

    class TestApp(EWrapper, EClient):
        def __init__(self):
            EClient.__init__(self, self)
            self.exp = []
            self.conid = 0

        def error(self, reqId, errorCode, errorString):
            print("Error: ", reqId, " ", errorCode, " ", errorString)

        def nextValidId(self, orderId):
            self.start()

        def contractDetails(self, reqId, contractDetails):
            self.conid = contractDetails.underConId
            print(contractDetails.underConId)

        def securityDefinitionOptionParameter(self, reqId:int, exchange:str,
                                              underlyingConId:int, tradingClass:str,
                                              multiplier:str, expirations:SetOfString,
                                              strikes:SetOfFloat):
            if exchange == 'SMART':
                s = list(expirations)
                s.sort(key=lambda date: datetime.strptime(date, "%Y%m%d"))
                self.exp = list(s)

        def start(self):
            # 265598 is the conId (contract ID) for AAPL Nasdaq stock
            contract = Contract()
            contract.symbol = stock
            contract.secType = "OPT"
            contract.exchange = "SMART"
            contract.currency = "USD"
            contract.strike = 150
            contract.right = "C"
            contract.multiplier = "100"
            contract.lastTradeDateOrContractMonth = "20211119"
            self.reqContractDetails(1, contract)
            self.reqSecDefOptParams(1, stock, "", "STK", 265598) 
            #sollte so aussehen: self.reqSecDefOptParams(1, stock, "", "STK", conid)

        def stop(self):
            self.done = True
            self.disconnect()

    app = TestApp()
    app.nextOrderId = 0
    app.connect("127.0.0.1", 7496, 60)
    Timer(1, app.stop).start()
    app.run()
    return app.exp

stock = 'AAPL'

x=exp(stock)
print(x)
In der Funktion "contractDetails" bekomme ich den Wert "contractDetails.underConId" und schreibe diesen in self.conid.
Wie stelle ich es an, dass ich statt "265598" die Variable "conid" an "reqSecDefOptParams" übergeben kann?

Danke
Mirko
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Man definiert keine Funktionen oder gar Klassen innerhalb von anderen Funktionen. Die Funktion `exp` gehört weg und `stock` sollte ein Attribut von TestApp sein.
Du weißt, wie man conid als Attribut setzt, aber nicht, wie man es wieder liest? Genauso.
Benutzeravatar
sparrow
User
Beiträge: 4231
Registriert: Freitag 17. April 2009, 10:28

Und Importe gehören an den Anfang des Moduls und nicht in irgendwelche Klassen oder Funktionen.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Der Grund für exp() ist, dass ich diese Funktion später aus einem anderen Script aufrufen möchte und dabei die Variable "stock" übergeben will.
Sprich exp('AAPL') und das Script soll mir die conid per "def contractDetails" ermiiteln, welche ich für "def securityDefinitionOptionParameter" benötige.
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Du kannst Dir ja so eine Funktion schreiben, aber da drin ist denn nur das Erzeugen der Klasseninstanz und nicht gleich die ganze Definitionen.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Ich glaub, jetzt komm ich nicht mehr mit. Kannst du das mal kurz beschreiben?
Benutzeravatar
pillmuncher
User
Beiträge: 1485
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@mirko3107: Vergleich mal das:

Code: Alles auswählen

def foo():
    class Bar:
        def baz(self):
            return 123
    b = Bar()
    return b.baz()
mit dem hier:

Code: Alles auswählen

class Bar:
    def baz(self):
        return 123

def foo():
    b = Bar()
    return b.baz()
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Dein Code sollte von der Struktur ungefähr so aussehen:

Code: Alles auswählen

# als erstes alle Importe
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
...

# dann Klassen
class TestApp(EWrapper, EClient):
    
    def __init__(self stock):
        self.stock = stock
        ...

# und Funktionen
def exp(stock):
    app = TestApp(stock)
    ...
Ob du dabei zuerst die Klassen und danach die Funktionen definierst oder umgekehrt ist oft egal (es gibt Spezialfälle, bei denen ist es nicht egal, z.B. Dekoratoren – aber das nur der Vollständigkeit halber). Es sollte aber kein schwer zu durchblickendes Durcheinander sein.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Hab das Script etwas angepasst:

Code: Alles auswählen

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.common import SetOfString
from ibapi.common import SetOfFloat
from ibapi.contract import Contract
from threading import Timer
from datetime import datetime

class TestApp(EWrapper, EClient):
    def __init__(self, stock):
        EClient.__init__(self, self)
        self.stock = stock
        self.exp = []
        self.conid = 0

    def error(self, reqId, errorCode, errorString):
        print(errorCode, " ", errorString)

    def nextValidId(self, orderId):
        self.start()

    def contractDetails(self, reqId, contractDetails):
        self.conid = contractDetails.underConId

    def securityDefinitionOptionParameter(self, reqId:int, exchange:str,
                                          underlyingConId:int, tradingClass:str,
                                          multiplier:str, expirations:SetOfString,
                                          strikes:SetOfFloat):
        if exchange == 'SMART':
            s = list(expirations)
            s.sort(key=lambda date: datetime.strptime(date, "%Y%m%d"))
            self.exp = list(s)

    def start(self):
    # 265598 is the conId (contract ID) for AAPL Nasdaq stock
        contract = Contract()
        contract.symbol = self.stock
        contract.secType = "OPT"
        contract.exchange = "SMART"
        contract.currency = "USD"
        contract.strike = 150
        contract.right = "C"
        contract.multiplier = "100"
        contract.lastTradeDateOrContractMonth = "20211119"
        self.reqContractDetails(1, contract)
        self.reqSecDefOptParams(1, self.stock, "", "STK", 265598)
        #sollte so aussehen: self.reqSecDefOptParams(1, stock, "", "STK", conid)
    def stop(self):
        self.done = True
        self.disconnect()

def exp(stock):
    #stock = 'AAPL'
    app = TestApp(stock)
    app.nextOrderId = 0
    app.connect("127.0.0.1", 7496, 60)
    Timer(2, app.stop).start()
    app.run()
    return app.conid, app.exp

x=exp('AAPL')
print(x)
Jetzt muss ich es noch hinbekommen, dass ich conid an "self.reqSecDefOptParams" übergebe.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wieso ist conid für dich so ein Problem, wenn du in der gleich Methode problemlos mit self.stock hantierst?
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Ich bekomme ja self.conid aus "self.reqContractDetails(1, contract)) per

Code: Alles auswählen

self.conid = contractDetails.underConId
Wenn ich aber self.conid an self.reqSecDefOptParams übergebe, ist sie leer.

Wahrscheinlich hab ich einen Denkfehler, ich suche weiter.
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann wird `contractDetails` nie aufgerufen. Jedenfalls nicht bevor nextValidId aufgerufen wird. Um das zu klären mußt Du wohl die Dokumentation zu ibapi lesen, oder jemanden finden, der sich mit dieser Bibliothek auskennt.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

die Funktion exp() spuckt mir die conid aus, das funktioniert.

Ich glaube, ich muss das Script nochmal umbauen, da beide Funktionen wohl gleichzeitig ausgeführt werden und nicht nacheinander.
mirko3107
User
Beiträge: 75
Registriert: Freitag 23. April 2021, 15:42

Ich habe jetzt mal versucht, die Aufrufe von contractDetails und securityDefinitionOptionParameter zu trennen per time.sleep,
aber immernoch ohne Erfolg.

Code: Alles auswählen

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.common import SetOfString
from ibapi.common import SetOfFloat
from ibapi.contract import Contract
from threading import Timer
from datetime import datetime
import time

class TestApp(EWrapper, EClient):
    def __init__(self, stock):
        EClient.__init__(self, self)
        self.stock = stock
        self.exp = []
        self.conid = 0

    def error(self, reqId, errorCode, errorString):
        print(errorCode, " ", errorString)

    def nextValidId(self, orderId):
        contract = Contract()
        contract.symbol = self.stock
        contract.secType = "OPT"
        contract.exchange = "SMART"
        contract.currency = "USD"
        contract.strike = 150
        contract.right = "C"
        contract.multiplier = "100"
        contract.lastTradeDateOrContractMonth = "20211119"
        self.reqContractDetails(1, contract)
        time.sleep(2)
        self.start()

    def contractDetails(self, reqId, contractDetails):
        self.conid = contractDetails.underConId

    def securityDefinitionOptionParameter(self, reqId:int, exchange:str,
                                          underlyingConId:int, tradingClass:str,
                                          multiplier:str, expirations:SetOfString,
                                          strikes:SetOfFloat):
        if exchange == 'SMART':
            s = list(expirations)
            s.sort(key=lambda date: datetime.strptime(date, "%Y%m%d"))
            self.exp = list(s)

    def start(self):
        self.reqSecDefOptParams(1, self.stock, "", "STK", 265598)
        #sollte so aussehen: self.reqSecDefOptParams(1, stock, "", "STK", conid)
    def stop(self):
        self.done = True
        self.disconnect()

def exp(stock):
    app = TestApp(stock)
    app.nextOrderId = 0
    app.connect("127.0.0.1", 7496, 60)
    Timer(3, app.stop).start()
    app.run()
    return app.conid, app.exp

x=exp('AAPL')
print(x)
Antworten