Re: Dataframes aus verschiedenen Prozessen zusammenfügen
Verfasst: Donnerstag 8. Juli 2021, 12:45
Ich dachte gerade, dass es durch paralleles Abfragen der Server etwas schneller geht, als alles nacheinander abzufragen.
Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Naja, wie oben gezeigt: es ist halt nicht sehr sinnvoll, immer und immer wieder über dieselben Schlüssel auf immer und immer wieder dieselben Elemente desselben Dictionary zuzugreifen. Das ist völlig überflüssig, wenn dieses Dictionary entsprechend groß ist, dann ist das nun einmal teuer... und, wie gesagt: völlig überflüssig. Meine Alternative habe ich in meinen Codebeispielen gezeigt, andernfalls könnte allerdings auch ein memoryview auf diesen Teilausschnitt des "großen" Dictionary eine gute Idee sein. Und ansonsten, wie gesagt: measure, don't guess -- alles andere ist Kaffeesatzleserei.snafu hat geschrieben: Donnerstag 8. Juli 2021, 05:50 Der Aufbau einer Datenstruktur nimmt mit zunehmender Komplexität und Datenmenge natürlich auch mehr Zeit in Anspruch. Aber langsam im Vergleich wozu? Was wäre deine Alternative und warum sollte man diese anstelle von Wörterbüchern nutzen bzw welchen immensen Zeitgewinn brächte sie?![]()
Code: Alles auswählen
def yahoo():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'Name', 'Price', 'Change', 'Cap', 'EPS', 'Volumen', '52Whigh', '52Wlow', 'Rating'])
rows = len(watch.index)
while True:
run = time.time()
for i in range(0, rows):
try:
ticker = watch['Ticker'].values[i]
quote_url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols='+ticker
quote_req = requests.get(quote_url)
change = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketChangePercent', 0),2)
price = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketPrice', 0),2)
volume = quote_req.json()['quoteResponse']['result'][0].get('regularMarketVolume', 0)
W52high = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekHigh', 0),2)
W52low = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekLow', 0),2)
rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
rating=''
for i in rat1:
if i.isalpha():
rating = "".join([rating, i])
if 'epsCurrentYear' in quote_req.json()['quoteResponse']['result'][0]:
eps = round(quote_req.json()['quoteResponse']['result'][0].get('epsCurrentYear', 0),2)
else:
eps = '0'
cap = round(quote_req.json()['quoteResponse']['result'][0].get('marketCap', 0)/1000000000, 2)
#print(ticker,price,change,cap,eps,volume,W52high,W52low,rating)
watch.at[i, 'Price'] = price
watch.at[i, 'Change'] = change
watch.at[i, 'Cap'] = cap
watch.at[i, 'EPS'] = eps
watch.at[i, 'Volumen'] = volume
watch.at[i, '52Whigh'] = W52high
watch.at[i, '52Wlow'] = W52low
watch.at[i, 'Rating'] = rating
except (KeyError, IndexError, RemoteDataError) as error:
print(f"Failed reading {ticker}: {error}")
pass
watch.to_csv('pack1.csv', header=True, index=False)
end = time.time()
print('Yahoo',round(end-run,0))
time.sleep(600)
def rsi():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'RSI'])
rows = len(watch.index)
run1 = time.time()
while True:
for i in range(0, rows):
try:
ticker = watch['Ticker'].values[i]
rsi = pdr.get_data_yahoo(ticker, dt.datetime(2021, 5, 1), dt.datetime.now(),session=session)
#rsi = yf.download(ticker, dt.datetime(2021, 5, 1), dt.datetime.now())
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']
#time.sleep(1)
watch.at[i, 'RSI'] = round(rsi_value, 2)
#print(ticker,rsi_value)
except (KeyError, IndexError, RemoteDataError) as error:
print(f"Failed reading {ticker}: {error}")
watch.at[i, 'RSI'] = '0'
pass
watch.to_csv('rsi.csv', header=True, index=False, columns=['Ticker', 'RSI'])
end1 = time.time()
print('RSI',round(end1-run1,0))
time.sleep(1800)
def sma():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'SMA200'])
rows = len(watch.index)
run2 = time.time()
while True:
for i in range(0, rows):
try:
ticker = watch['Ticker'].values[i]
sma = pdr.get_data_yahoo(ticker, dt.datetime(2020, 5, 1),session=session)
#sma = yf.download(ticker, dt.datetime(2020, 5, 1))
sma['SMA10'] = sma['Close'].rolling(10).mean()
sma['SMA50'] = sma['Close'].rolling(50).mean()
sma['SMA200'] = sma['Close'].rolling(200).mean()
sma_value = sma.iloc[-1]['SMA200']
#print(ticker, sma_value)
watch.at[i, 'SMA200'] = round(sma_value, 2)
#time.sleep(1)
except (KeyError, IndexError, RemoteDataError) as error:
print(f"Failed reading {ticker}: {error}")
pass
watch.to_csv('sma.csv', header=True, index=False, columns=['Ticker', 'SMA200'])
end2 = time.time()
print('SMA:',round(end2-run2,0))
time.sleep(1800)
def stoch():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'Stoch'])
run3 = time.time()
rows = len(watch.index)
while True:
for i in range(0, rows):
try:
ticker = watch['Ticker'].values[i]
stoch = pdr.get_data_yahoo(ticker, dt.datetime(2021, 5, 1), dt.datetime.now(),session=session)
#stoch = yf.download(ticker, dt.datetime(2021, 5, 1), dt.datetime.now())
stoch['14-high'] = stoch['High'].rolling(14).max()
stoch['14-low'] = stoch['Low'].rolling(14).min()
stoch['%K'] = (stoch['Close'] - stoch['14-low']) * 100 / (stoch['14-high'] - stoch['14-low'])
stoch['%D'] = stoch['%K'].rolling(3).mean()
stoch2 = stoch.iloc[-1]['%D']
watch.at[i, 'Stoch'] = round(stoch2, 2)
#time.sleep(1)
#print(ticker,stoch2)
except (KeyError, IndexError, RemoteDataError) as error:
print(f"Failed reading {ticker}: {error}")
pass
watch.to_csv('stoch.csv', header=True, index=False, columns=['Ticker', 'Stoch'])
end3 = time.time()
print('Stoch:',round(end3-run3,0))
time.sleep(1800)
Code: Alles auswählen
def earnings_iv():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'Earnings', 'IV'])
rows = len(watch.index)
run4 = time.time()
while ib.isConnected():
for i in range(0, 10):
try:
ticker = watch['Ticker'].values[i]
contract = Stock(ticker, 'SMART', 'USD')
ib.reqMarketDataType(1)
ib.qualifyContracts(contract)
data = ib.reqMktData(contract, "106,100", False, False)
ib.sleep(1)
iv = round(data.impliedVolatility * 100, 2)
earn = ib.reqFundamentalData(contract, 'CalendarReport')
if type(earn) == str:
tree = ET.ElementTree(ET.fromstring(earn))
root = tree.getroot()
item = tree.find('.//Date')
earnings = item.text
else:
earnings = '01/01/2000'
print(ticker, earnings,iv)
watch.at[i, 'Earnings'] = earnings
watch.at[i, 'IV'] = iv
ib.cancelMktData(contract)
except (KeyError, IndexError) as error:
print(f"Failed reading {ticker}: {error}")
pass
ib.disconnect()
watch.to_csv('earnings_iv.csv', header=True, index=False, columns=['Ticker', 'Earnings', 'IV'])
end4 = time.time()
print('Stoch:',round(end4-run4,0))
time.sleep(3600)
Code: Alles auswählen
Exception in thread Thread-5:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/home/mirko/stocks/streamlit/test/thread_watch.py", line 161, in earnings_iv
ib.reqMarketDataType(1)
File "/home/mirko/.local/lib/python3.9/site-packages/ib_insync/ib.py", line 1118, in reqMarketDataType
self.client.reqMarketDataType(marketDataType)
File "/home/mirko/.local/lib/python3.9/site-packages/ib_insync/client.py", line 815, in reqMarketDataType
self.send(59, 1, marketDataType)
File "/home/mirko/.local/lib/python3.9/site-packages/ib_insync/client.py", line 265, in send
self.sendMsg(msg.getvalue())
File "/home/mirko/.local/lib/python3.9/site-packages/ib_insync/client.py", line 268, in sendMsg
loop = asyncio.get_event_loop()
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 'Thread-5'.
Das ist lieb, daß Du uns an Dinge erinnerst, die ich zwar schon lange weiß, die aber möglicherweise informativ und hilfreich für andere Mitlesende sind. Außerdem bieten numpy und das darauf basierende Pandas ja noch ein bisschen mehr als nur eine bessere Speichereffizienz.DasIch hat geschrieben: Donnerstag 8. Juli 2021, 09:07 Um mal "zentrales Element" von Sirius3 etwas auszuführen: In CPython ist im Prinzip jedes Objekt letztendlich ein Dictionary, ggfs. mit bisschen Kram drumherum. Jeder Attributzugriff macht mindestens einen dict lookup. Der Zugriff auf eine Variable, sofern sie nicht lokal zu einer Funktion sind, führt zu einem dict lookup. Das erstellen eines Objektes führt zwangsläufig auch dazu dass ein dict erstellt wird, es sei den man hat __slots__ definiert oder sie ist in C implementiert. Die Konsequenz ist natürlich auch dass das erstellen von allen Objekten viel speicherintensiver ist als es in z.B. C oder Rust wäre. Deswegen nutzt man ja übrigens auch Dinge wie numpy oder pandas.
Du solltest auch bedenken dass das anlegen von Objekten auf der Heap in Sprachen wie Python massiv optimiert ist und i.d.R. nicht einem naiven malloc() o.ä. wie in C oder C++ entspricht. Das anlegen von Objekten und damit auch dicts ist wahrscheinlich deutlich schneller als du erwartest.
Code: Alles auswählen
d['a']['b']['c'].get('eins')
d['a']['b']['c'].get(''zwei')
d['a']['b']['c'].get('drei')
d['a']['b']['c'].get('vier')
Code: Alles auswählen
dummy = d['a']['b']['c']
dummy.get('eins')
dummy.get(''zwei')
dummy.get('drei')
dummy.get('vier')
https://pandas.pydata.org/pandas-docs/s ... oncat.htmlmirko3107 hat geschrieben: Donnerstag 8. Juli 2021, 17:12 Den IB-Part lasse ich nun "normal" laufen, also ohne Threading, dauert ca. 1800s, liegt aber an der lahmen IB-API.
Meine Hauptfrage ist immer noch, wie ich die jeweiligen Dataframes aus den Threads nun in ein Gesamt-Dataframe bekomme.
Ich weiß nicht, welche Vorstellungen Du da hast. Dir sagt der Begriff "Referenz" etwas?LukeNukem hat geschrieben: Donnerstag 8. Juli 2021, 16:12 Nun könnte man zwar vermuten, daß die zweite Variante eine neue Speicherallokation provoziert, allerdings... einerseits optimiert Python hier schon ziemlich gut (warum gibt es eigentlich das Modul "copy"?) und auf der anderen Seite hat da womöglich auch das Betriebssystem bzw. dessen Speicherverwaltung noch etwas beizutragen, etwa mit Copy-On-Write und Same-Page-Merging.
Massendaten-Verarbeitung mit Python als Randbereich anzupreisen, lässt schon tief blicken. Das macht dich nicht zum Guru und dies zeigen auch deine Aussagen hier im Thread. Du scheinst dich ja echt sehr oft missverständlich auszudrücken. Oder will sich vielleicht jemand herausreden, wenn er korrigiert wird...?LukeNukem hat geschrieben: Donnerstag 8. Juli 2021, 16:12 das Dumme ist halt, daß ich in den letzten acht Jahren beruflich wenig anderes gemacht habe als Massendatenverarbeitung unter Echtzeitbedingungen, genauer: die Verarbeitung von Transaktionsdaten zur Betrugsdetektion und -prävention. Wenn man so etwas über längere Zeiträume hinweg macht, dann gewinnt man eine... ziemlich innige Beziehung dazu, was eine Skriptsprache auf dem System und was das System dann auf der Hardware macht. Insofern habe ich vielleicht ein bisschen Erfahrung in Randbereichen, die die meisten anderen Entwickler vielleicht nicht jeden Tag sehen, und versuche meine Erfahrungen aus diesen Bereichen hier einzubringen.
Code: Alles auswählen
def yahoo():
watch = pd.read_csv("watch.csv", usecols=['Ticker', 'Name', 'Price', 'Change', 'Cap', 'EPS', 'Volumen', '52Whigh', '52Wlow', 'Rating'])
rows = len(watch.index)
while True:
run = time.time()
for i in range(0, rows):
try:
ticker = watch['Ticker'].values[i]
quote_url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols='+ticker
quote_req = requests.get(quote_url)
change = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketChangePercent', 0),2)
price = round(quote_req.json()['quoteResponse']['result'][0].get('regularMarketPrice', 0),2)
volume = quote_req.json()['quoteResponse']['result'][0].get('regularMarketVolume', 0)
W52high = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekHigh', 0),2)
W52low = round(quote_req.json()['quoteResponse']['result'][0].get('fiftyTwoWeekLow', 0),2)
rat1 = quote_req.json()['quoteResponse']['result'][0].get('averageAnalystRating', 'None')
rating=''
for i in rat1:
if i.isalpha():
rating = "".join([rating, i])
if 'epsCurrentYear' in quote_req.json()['quoteResponse']['result'][0]:
eps = round(quote_req.json()['quoteResponse']['result'][0].get('epsCurrentYear', 0),2)
else:
eps = '0'
cap = round(quote_req.json()['quoteResponse']['result'][0].get('marketCap', 0)/1000000000, 2)
#print(ticker,price,change,cap,eps,volume,W52high,W52low,rating)
watch.at[i, 'Price'] = price
watch.at[i, 'Change'] = change
watch.at[i, 'Cap'] = cap
watch.at[i, 'EPS'] = eps
watch.at[i, 'Volumen'] = volume
watch.at[i, '52Whigh'] = W52high
watch.at[i, '52Wlow'] = W52low
watch.at[i, 'Rating'] = rating
except (KeyError, IndexError, RemoteDataError) as error:
print(f"Failed reading {ticker}: {error}")
pass
watch.to_csv('pack1.csv', header=True, index=False)
time.sleep(600)
Code: Alles auswählen
import aiohttp
import asyncio
import time
import statistics
loop = asyncio.get_event_loop()
async def get_result():
async with aiohttp.ClientSession() as session:
async with session.get(
"https://query1.finance.yahoo.com/v7/finance/quote?symbols=GOOG"
) as response:
response.raise_for_status()
return await response.json()
async def no_data_storage():
await asyncio.gather(*[get_result() for _ in range(1000)])
async def with_data_storage():
response = await asyncio.gather(*[get_result() for _ in range(1000)])
def measure(measure_func):
times = []
for _ in range(10):
start = time.perf_counter()
loop.run_until_complete(measure_func())
delta = time.perf_counter() - start
times.append(delta)
print(f"{delta:10.3f} s")
print(f"Durchschnitt: {statistics.mean(times):0.3f}")
print("Ohne Speichern")
measure(no_data_storage)
print()
print("Mit Speichern")
measure(with_data_storage)
Code: Alles auswählen
Ohne Speichern
14.601 s
27.252 s
20.859 s
43.963 s
33.140 s
28.015 s
16.654 s
18.356 s
15.417 s
20.989 s
Durchschnitt: 23.925
Mit Speichern
21.014 s
20.790 s
27.653 s
19.263 s
19.793 s
29.764 s
27.843 s
18.609 s
28.514 s
27.414 s
Durchschnitt: 24.066
In dem genannten Umfeld und dort insbesondere im Echtzeitbereich gibt's da nicht so viele.snafu hat geschrieben: Donnerstag 8. Juli 2021, 19:37 Massendaten-Verarbeitung mit Python als Randbereich anzupreisen,
Hat auch keiner behauptet, oder?
Es würde die Mißverständnisse wesentlich reduzieren, wenn Du meine Ausführungen vollständig läsest und Deine Energie in deren Verständnis investieren würdest, anstatt mit Strohpuppen zu "argumentieren".snafu hat geschrieben: Donnerstag 8. Juli 2021, 19:37 Du scheinst dich ja echt sehr oft missverständlich auszudrücken.
Na klar.snafu hat geschrieben: Donnerstag 8. Juli 2021, 19:37 Oder will sich vielleicht jemand herausreden, wenn er korrigiert wird...?![]()
Tatsächlich hatte es in älteren Python-Versionen sogar etwas mit den Inhalten der Schlüssel zu tun und hat bis heute etwas mit der Schlüssellänge zu tun. Und wenn der Worst Case O(n) ist, dann hat die Größe des Schlüsslraums (dieses ominöse n in O(n)) natürlich eine entsprechend größere Auswirkung auf die Performance, wenn der Worst Case eintritt.__blackjack__ hat geschrieben: Donnerstag 8. Juli 2021, 22:32 @LukeNukem: Der amortisierte „worst case“ hat nichts mit der Grösse des Wörterbuchs zu tun. Ich weiss nicht wo Du das aus der Wikiseite heraus liest. Der betrifft *jede* Wörterbuchgrösse.
Code: Alles auswählen
func1() = count: 50, alltime: 66390.4 µs
func2() = count: 50, alltime: 1510.2 µs
func5() = count: 50, alltime: 1339.9 µs
Nix "premature". "Measure, don't guess".__deets__ hat geschrieben: Freitag 9. Juli 2021, 09:30 "Premature Optimization, the root of all evil."
Na klar.__deets__ hat geschrieben: Freitag 9. Juli 2021, 09:30 Ausser es handelt sich um "premature micro-optimization for the sole purpose to not admit that I justified my remarks in the wrong way is A-ok!".
Niemand, wirklich niemand hat behauptet, daß diese Zugriffe "unfassbar teuer waeren", wie Du behauptest. Meine Aussage war:__deets__ hat geschrieben: Freitag 9. Juli 2021, 09:30 Niemand, wirklich niemand hier, hat behauptet, dass es nicht besser waere, solche geschachtelten Zugriffe zu vermeiden. Nur eben nicht, weil sie so unfassbar teuer waeren, wie du behauptest.
Genau das habe ich geschrieben. Und mittlerweile belegt. Elf Prozent Laufzeitdifferenz finde ich für ein Feature, dessen Zeitkomplexität O(1) hier als "so schnell, daß es vernachlässigbar ist" verstanden zu werden und dessen Worst Case O(n) geflissentlich übersehen zu werden scheint, immer noch enorm. Dabei sagt die Zeitkomplexität O(1) natürlich gar nichts über den tatsächlichen Zeitbedarf eines Zugriffs, sondern nur, daß die tatsächlich benötigte Zeit unabhängig von der Anzahl der Elemente ist. Also, im Idealfall. Und unter gleichbleibenden Randbedingungen.LukeNukem hat geschrieben: Mittwoch 7. Juli 2021, 19:01 Dictionaries sind jetzt auch nicht unbedingt das performanteste Feature von Python.