Dataframes aus verschiedenen Prozessen zusammenfügen
Ungetestet:mirko3107 hat geschrieben: ↑Samstag 10. Juli 2021, 11:12Oder gibts da noch bessere Möglichkeit als nur Buchstaben rausfiltern?Code: Alles auswählen
rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None') rating='' for i in rat1: if i.isalpha(): rating = "".join([rating, i])
Code: Alles auswählen
def filter_alpha(value):
if isinstance(value, (bytes, str)):
return ''.join([c for c in value if c.isalpha()])
return value
df.rating = df.rating.apply(filter_alpha).astype('category')
[1] https://pandas.pydata.org/pandas-docs/s ... rical.html
Du hast ja mehrere Teile, die die Daten aus unterschiedlichen Quellen ziehen und dann, zumindest teilweise, auf eine recht ähnliche Art konvertieren. Also nimmst Du Dir Deine anderen Programmteile und baust sie nach dem Vorbild um, das ich gezeigt habe. Das baust Du dann in den Hauptteil -- also: dem Teil unter "if __name__ ==..." ein, erzeugst aus Deinen neuen Klassen (bei mir: "YahooFun") also Instanzen (bei mir: "yf = YahooFun()"), übergibst die "Arbeitsfunktionen" (bei mir: "yahoo()") Deinem ThreadPoolExecutor und hängst die future-Objekte mit += an die Variable "futures" an.
Am Ende -- also: wenn alles durchgelaufen ist und alle future-Objekte in "futures" mit "result()" ihre Ergebnisse geliefert haben -- ziehst Du aus den genannten Instanzen dann Deine Pandas-DataFrames, wie ich in der letzten Zeile, baust mit "pandas.concat()" einen großen Ergebnis-Dataframe, und dann kannst Du damit viele lustige Dinge machen: sie einfach schnöde ausgeben, mit Altair oder Bokeh hübsche Plots daraus erzeugen, ganz wie Du lustig bist. Vorher würde ich Dir allerdings empfehlen, mal ein Python- und ein Pandas-Tutorial durchzuarbeiten... Viel Erfolg!
Wenn ich über die gleiche URL wie die anderen Werte den Wert "averageAnalystRating" abfrage, bekomm ich ab der Hälfte der Ticker-Werte keinen Wert mehr ausgelesen,LukeNukem hat geschrieben: ↑Sonntag 11. Juli 2021, 22:40Ungetestet:mirko3107 hat geschrieben: ↑Samstag 10. Juli 2021, 11:12Oder gibts da noch bessere Möglichkeit als nur Buchstaben rausfiltern?Code: Alles auswählen
rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None') rating='' for i in rat1: if i.isalpha(): rating = "".join([rating, i])
Das ".astype()" muß nicht, konvertiert die Daten aber in kategorische Variablen, siehe dazu [1].Code: Alles auswählen
def filter_alpha(value): if isinstance(value, (bytes, str)): return ''.join([c for c in value if c.isalpha()]) return value df.rating = df.rating.apply(filter_alpha).astype('category')
[1] https://pandas.pydata.org/pandas-docs/s ... rical.html
alle anderen funktionieren weiterhin. Der Wert verschwindet scheinbar, auch wenn man im Browser den Link zu oft abfragt.
Ich bleib dann bei meiner anderen URL, die scheint dauerhaft zu funktionieren.
Möglich, ja. Einige andere Beitragende in diesem Thread haben ja schon angedeutet, daß es da serverseitige Limitierungen gibt -- und bei Yahoo ist es sogar so, daß offenbar auch der User-Agent geprüft wird.mirko3107 hat geschrieben: ↑Montag 12. Juli 2021, 09:53 Wenn ich über die gleiche URL wie die anderen Werte den Wert "averageAnalystRating" abfrage, bekomm ich ab der Hälfte der Ticker-Werte keinen Wert mehr ausgelesen,
alle anderen funktionieren weiterhin. Der Wert verschwindet scheinbar, auch wenn man im Browser den Link zu oft abfragt.
Es ist halt so, daß die Börsenbetreiber und verschiedene andere tatsächlich bemerkt haben, daß man Börsentickerdaten a) für gutes Geld verkaufen kann, man b) mit reinen Datenabfragen keine Werbeeinnahmen generiert, und c), daß der Betrieb eigener Server nun einmal Geld kostet -- und daß diese Server und deren Betrieb immer teurer werden, je häufiger jemand diese Daten abfragt und je mehr Jemande das tun.
Insofern bieten sich Dir nun verschiedene Möglichkeiten: die Anzahl Deiner Abfragen so zu reduzieren und / oder zu verlangsamen, daß sie die serverseitigen Rate Limits nicht auslösen. Das kann Dir allerdings morgen oder übermorgen wieder auf die Füße fallen, wenn der Anbieter Deiner Daten entscheidet, die Rate Limits zu verschärfen. Du kannst natürlich auch Deine aktuelle Strategie weiterverfolgen und Deine Daten aus verschiedenen freien Quellen zusammenstoppeln, aber das birgt verschiedene Gefahren: die Daten könnten veraltet oder auf mehr oder weniger subtile Weise inkonsistent sein, und jeder neue Anbieter könnte von heute auf morgen entscheiden, Deine Quellen abzuschalten, neue oder verschärfte Rate Limits einzuführen, ... oder, und, oder.
Die letzte Möglichkeit ist daher, ich weiß, ein bisschen unkonventionell, langfristig jedoch die vermutlich stabilste Lösung: Du suchst Dir einen kommerziellen Anbieter und bezahlst für Deine Daten... und natürlich für die Server und deren Betreiber, die Dir diese Daten bereitstellen.
HTH, YMMV.
Sollte ich die RSI/SMA-Berechnung auch mit in die yahoo-Funktion einbauen oder eine eigene Funktion dafür erstellen?LukeNukem hat geschrieben: ↑Sonntag 11. Juli 2021, 22:51Du hast ja mehrere Teile, die die Daten aus unterschiedlichen Quellen ziehen und dann, zumindest teilweise, auf eine recht ähnliche Art konvertieren. Also nimmst Du Dir Deine anderen Programmteile und baust sie nach dem Vorbild um, das ich gezeigt habe. Das baust Du dann in den Hauptteil -- also: dem Teil unter "if __name__ ==..." ein, erzeugst aus Deinen neuen Klassen (bei mir: "YahooFun") also Instanzen (bei mir: "yf = YahooFun()"), übergibst die "Arbeitsfunktionen" (bei mir: "yahoo()") Deinem ThreadPoolExecutor und hängst die future-Objekte mit += an die Variable "futures" an.
Am Ende -- also: wenn alles durchgelaufen ist und alle future-Objekte in "futures" mit "result()" ihre Ergebnisse geliefert haben -- ziehst Du aus den genannten Instanzen dann Deine Pandas-DataFrames, wie ich in der letzten Zeile, baust mit "pandas.concat()" einen großen Ergebnis-Dataframe, und dann kannst Du damit viele lustige Dinge machen: sie einfach schnöde ausgeben, mit Altair oder Bokeh hübsche Plots daraus erzeugen, ganz wie Du lustig bist. Vorher würde ich Dir allerdings empfehlen, mal ein Python- und ein Pandas-Tutorial durchzuarbeiten... Viel Erfolg!
Für die Datenabfrage zu IB wäre sicherlich eine neue Class nötig, oder?
Dass wir jetzt wieder an dem Punkte angelangt sind, auf den so viele schon von Anfang an hingewiesen hatten, ist dann aber doch irgendwie bemerkenswert.Insofern bieten sich Dir nun verschiedene Möglichkeiten: die Anzahl Deiner Abfragen so zu reduzieren und / oder zu verlangsamen, daß sie die serverseitigen Rate Limits nicht auslösen.
Warum eine Tankstelle kaufen, wenn man nur tanken will?Lösung: Du suchst Dir einen kommerziellen Anbieter und bezahlst für Deine Daten... und natürlich für die Server und deren Betreiber, die Dir diese Daten bereitstellen
Der kommerzielle Anbieter ist Yahoo (Oder jede andere Plattform, die Finanzdaten zur Verfügung stellt). Nur muss man denen eben ein bischen Geld geben wenn man große Mengen an Daten ziehen will.
@LukeNukem: Ich muss mittlerweile zugeben, ich bekomm es nicht so eingebaut, wie du es mir vorgeschlagen hast. Könntest du mir noch einen kleinen Tip geben oder einen Einstieg, wie ich das am besten umsetze?
Momentan hab ich die ganzen Berechnungssachen mit in die yahoo-Funktion eingebaut, aber ich denke mal, so war das von dir nicht gemeint.
Momentan hab ich die ganzen Berechnungssachen mit in die yahoo-Funktion eingebaut, aber ich denke mal, so war das von dir nicht gemeint.
Na klar, gerne... aber ich bin mir nicht ganz sicher, ob er Dir gefallen wird. Mein Tipp ist, erst die Grundlagen von Python und dann die von Pandas zu lernen. Also... nicht den Schlangen und den Bären, wohlgemerkt.
Naja... mein ganzer Ansatz ist halt ein anderer als Deiner. Und damit meine ich nicht die Datenverarbeitung, sondern vor allem das Laufzeitmodell.
Mein Programmdesign betreibt einen zentralen ThreadPoolExecutor. Der ist dazu da, Deine Funktionen zu verwalten. Dem kannst Du (im Prinzip) so viele Funktionen übergeben, wie Du willst. Das können auch ganz verschiedene Funktionen sein: er wird sie in einem seiner Threads aufrufen, abwarten bis sie durchgelaufen ist und ein Ergebnis produziert hat. Und dann nimmt er sich die nächste wartende Funktion vor... so lange, bis alle Funktionen abgearbeitet sind [1]. Yay!
Außerdem gibt es einen zweiten großen Designunterschied: ich betrachte jeden Download -- also: jeden Ticker von jeder URL -- als einen Funktionsaufruf. (Eigentlich einen Methodenaufruf, aber geschenkt...) Dagegen betrachtet Deine Software jede Quelle als einen Funktionsaufruf. Anders gesagt: Du hast für jede Quelle eine Funktion, die aufgerufen wird, ich dagegen habe eine Funktion (Methode), die für jede Quelle + Ticker an den ThreadPoolExecutor übergeben wird.
Diese beiden Umstände bedeuten im Umkehrschluß: entweder, Du behältst Dein bisheriges Design bei und kannst dann höchstens meine Ideen zum Auslesen der Daten aus den Responses übernehmen. Oder, Du wirfst Deine bisherigen Lösungsansätze über den Haufen und baust Deine Software nach meinem Design um. Zumindest der zweite Ansatz wird es allerdings erfordern, daß Du Dir die Grundlagen von Python und die von Pandas aneignest. Und genau das möchte ich Dir aller-, aller-, aller- und allerwärmstens empfehlen. Die Idee meiner Idee ist nicht, sie zu kopieren. Sondern, sie zu verstehen und zu adaptieren.
[1] Für meine pedantisch orientierten Freunde: das ist nur teilweise korrekt, aber sei's drum.
Ich hab jetzt alles, was von yahoo kommt, in die Yahoo-Class eingebaut, da lieg ich pro Abruf bei knapp 1s, völlig ausreichend.
Ich habe jetzt versucht, den IB-Part einzubauen, aber da meldet er mir folgendes:
Ich habe jetzt versucht, den IB-Part einzubauen, aber da meldet er mir folgendes:
Code: Alles auswählen
File "/usr/lib/python3.9/asyncio/events.py", line 642, in get_event_loop
raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-0_0'.
sys:1: RuntimeWarning: coroutine 'IB.connectAsync' was never awaited
Das hatten wir doch schon vor Tagen. Sowohl multiprocessing als auch threads sind falsch. Schreibe asynchron Funktionen. Lass dich von anderen Mitschreibenden nicht in die Irre führen. Am besten fängt man mit einem sehr einfachen Beispiel an, dass z.b. asynchrone Funktionsaufrufen verschiedene Dataframes zurückgeben, die Du dann zu kombinieren versuchst.
@mirko3107,
wenn du nach "ib_insync threading" suchst, wirst du schnell merken, dass du nicht der einzige bist, der es so versucht hat und nicht weiter gekommen ist.
Die Antwort war aber immer: "Benutze asyncio"
Ich kann die Hemmschwelle bzgl. asyncio durchaus verstehen. So schwer ist es aber gar nicht wenn man sich etwas einliest.
ib_insync ist so geschrieben, dass es sich nach außen anfühlt, als ob es einfach synchron abläuft. Das funktioniert bei einzelnen Datenabfragen auch noch problemlos. Wenn man aber mal in den Sourcecode schaut, sieht man, dass alle Datenabfragen asynchron ablaufen.
Daher würde jeder, der sich da ein wenig auskennt, die Applikation drum herum auch asynchron schreiben.
Ich kann es bei mir leider nicht ausprobieren, da man dafür anscheinen einen Zugang braucht.
Das ist das Beispiel aus der ib_insync Dokumentation mit asynchronem Aufruf für mehrere Symbole.
So würde ich anfangen, wenn ich es ausprobieren könnte. Nur ein Versuch und ungetestet.
(Wie man sich die Daten von Yahoo holt, hatte ich ja schon in einem früheren Post gezeigt)
wenn du nach "ib_insync threading" suchst, wirst du schnell merken, dass du nicht der einzige bist, der es so versucht hat und nicht weiter gekommen ist.
Die Antwort war aber immer: "Benutze asyncio"
Ich kann die Hemmschwelle bzgl. asyncio durchaus verstehen. So schwer ist es aber gar nicht wenn man sich etwas einliest.
ib_insync ist so geschrieben, dass es sich nach außen anfühlt, als ob es einfach synchron abläuft. Das funktioniert bei einzelnen Datenabfragen auch noch problemlos. Wenn man aber mal in den Sourcecode schaut, sieht man, dass alle Datenabfragen asynchron ablaufen.
Daher würde jeder, der sich da ein wenig auskennt, die Applikation drum herum auch asynchron schreiben.
Ich kann es bei mir leider nicht ausprobieren, da man dafür anscheinen einen Zugang braucht.
Das ist das Beispiel aus der ib_insync Dokumentation mit asynchronem Aufruf für mehrere Symbole.
So würde ich anfangen, wenn ich es ausprobieren könnte. Nur ein Versuch und ungetestet.
(Wie man sich die Daten von Yahoo holt, hatte ich ja schon in einem früheren Post gezeigt)
Code: Alles auswählen
import asyncio
from ib_insync import IB, Forex
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)
async def get_data(symbol):
contract = Forex(symbol)
bars = await ib.reqHistoricalData(
contract, endDateTime='', durationStr='30 D',
barSizeSetting='1 hour', whatToShow='MIDPOINT', useRTH=True)
return bars
async def main():
# holt die historischen Daten der angegebenen Symbole
all_data = await asyncio.gather(*[get_data(symbol) for symbol in ["FOREX", "AMZN", "GOOG"]])
# all_data enthält Liste aller Daten
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Ich habe jetzt einiges probiert, aber mit wenig Erfolg.
Ich hab mein Script vom Beginn mal wieder rausgekramt und wollte da Dinge einbauen, die in den letzten Tage denke gelernt zu haben, besser gesagt gelesen.
Das Script funktioniert im Grunde, nicht schön wie ihr durchaus bemerkt habt, aber läuft.
Wenn ich aus meiner CSV-Datei per
eine Ticker-Liste erstelle und diese dann per
an den jeweiligen Prozess schicke, läuft zb. dieser hier durch:
Wie bekomm ich die Ergebnisse dieses Prozesses wieder aus diesem heraus?
Vielen Dank
Ich hab mein Script vom Beginn mal wieder rausgekramt und wollte da Dinge einbauen, die in den letzten Tage denke gelernt zu haben, besser gesagt gelesen.
Das Script funktioniert im Grunde, nicht schön wie ihr durchaus bemerkt habt, aber läuft.
Wenn ich aus meiner CSV-Datei per
Code: Alles auswählen
yf_df = pd.read_csv(file, sep=',')
tickers = yf_df.Ticker.tolist()
Code: Alles auswählen
p1 = multiprocessing.Process(target=rsi, args = (tickers, ))
Code: Alles auswählen
def rsi(tickers):
rsilist = []
while True:
for ticker in tickers:
try:
rsi = pdr.get_data_yahoo(ticker, dt.datetime(2021, 5, 1), dt.datetime.now(),session=session)
delta = rsi['Close'].diff()
up = delta.clip(lower=0)
down = -1 * delta.clip(upper=0)
ema_up = up.ewm(com=13, adjust=False).mean()
ema_down = down.ewm(com=13, adjust=False).mean()
rs = ema_up / ema_down
rsi['RSI'] = 100 - (100 / (1 + rs))
rsi_value = rsi.iloc[-1]['RSI']
print(ticker, rsi_value)
rsilist.append(rsi_value)
except Exception as e:
logging.exception('Something went terribly wrong')
return [0.0] * 4
Vielen Dank
Naja, wenn Du es mit Multiprocessing machst, dann müssen die Daten natürlich vom sendenden Prozeß serialisiert werden -- etwa mit pandas.DataFrame.to_pickle() und vom lesenden Prozeß wieder deserialisiert werden, beispielsweise mit pandas.read_pickle(). Aber die Kollegen haben natürlich Recht: wenn dieses ib-Dingsi asynchron arbeitet, solltest Du beim Rest ebenfalls asynchron arbeiten. Man kann die Ansätze zwar mischen, aber... dazu sollte man UNBEDINGT und sehr GENAU wissen, was man tut und warum man es tut.
Also mit async und ib_insync hatte ich bisher keinen Erfolg, per multiprocessing läuft es aber, reicht mir völlig.
MIt multiprocessing.Pool ist es aber nicht möglich, Funktionen parallel auszuführen, oder?
Hab einen Pool für yahoo mit 4 Prozessen und einen Pool für ib_insync mit 1 Prozess, welche aber nacheinander laufen.
MIt multiprocessing.Pool ist es aber nicht möglich, Funktionen parallel auszuführen, oder?
Hab einen Pool für yahoo mit 4 Prozessen und einen Pool für ib_insync mit 1 Prozess, welche aber nacheinander laufen.