Handeln, wenn der Markt handelt
Der volumengewichtete Durchschnittspreis ist der Durchschnittspreis alles Gehandelten, jeder Trade nach seiner Größe gewichtet: sum(price * volume) / sum(volume). Er ist der häufigste Benchmark im institutionellen Handel, weil er zeigt, was ein durchschnittlicher Teilnehmer an diesem Tag gezahlt hat. Ein VWAP-Algorithmus versucht, ihn zu erreichen oder zu schlagen, indem er *proportional zum Marktvolumen* handelt: viel, wenn der Markt lebhaft ist (Eröffnung, Schluss), wenig, wenn er ruhig ist (Mittagszeit). Wo TWAP der Uhr folgt, folgt VWAP der Menge, sodass jede Ihrer Orders ein ähnlicher Bruchteil dessen ist, was alle anderen tun, und den Preis weniger bewegt.
# The benchmark: each price counts as much as the volume that traded at it
def vwap(prices, volumes):
return sum(p * v for p, v in zip(prices, volumes)) / sum(volumes)
prices = [100.0, 101.0, 102.0]
volumes = [100, 300, 600]
print(round(vwap(prices, volumes), 4)) # 101.5 most volume traded near 102, so the VWAP leans that way
print(sum(prices) / len(prices)) # 101.0 the plain average ignores how much traded at each priceEin Volumenprofil und ein Plan, der ihm folgt
Das heutige Volumen kennt man nicht im Voraus, deshalb nutzt ein VWAP-Algorithmus ein aus der Historie geschätztes Volumenprofil: den durchschnittlichen Anteil des Tagesvolumens, der in jedem Intervall gehandelt wurde, über etwa die letzten 20 Sitzungen. Das Intraday-Volumen ist typischerweise U-förmig, hoch bei Eröffnung und Schluss. Der Plan gibt jedem Intervall dann total * Anteil Aktien. Das sind selten ganze Zahlen, und jedes einzeln zu runden kann Aktien verlieren oder hinzufügen. Die Methode des größten Rests behebt das: Geben Sie jedem Intervall den abgerundeten Wert und verteilen Sie die übrigen Aktien, je eine, an die Intervalle mit den größten Nachkommaanteilen, sodass der Plan immer die Order ergibt.
# From volumes to a profile, then to whole shares by the largest remainder method
import math
def volume_profile(volumes):
total = sum(volumes)
return [v / total for v in volumes]
def vwap_schedule(total, profile):
exact = [total * share for share in profile]
shares = [math.floor(value + 1e-9) for value in exact]
leftover = total - sum(shares)
for index in sorted(range(len(profile)), key=lambda i: (-(exact[i] - shares[i]), i))[:leftover]:
shares[index] += 1
return shares
profile = volume_profile([300, 100, 100, 200, 500, 800]) # a U-shape: busy at the open and the close
print([round(p, 3) for p in profile]) # [0.15, 0.05, 0.05, 0.1, 0.25, 0.4]
print(vwap_schedule(1003, profile)) # [151, 50, 50, 100, 251, 401] adds up to 1003
print(sum(vwap_schedule(1003, profile))) # 1003Beteiligungsgrenzen und das Verfolgen des Benchmarks
Ein Plan ist ein Plan; der Markt kann ruhiger sein, als das Profil vorhersagte. Eine Beteiligungsgrenze begrenzt Ihren Handel in jedem Intervall auf einen Bruchteil des tatsächlichen Marktvolumens darin, etwa 10 %, sodass Sie nie den Großteil des Flusses ausmachen. Aktien, die Sie nicht handeln konnten, werden auf spätere Intervalle vorgetragen, was am Ende einen Rest unausgeführt lassen kann; dann entscheiden Sie, ob Sie mehr Risiko eingehen, das Fenster verlängern oder aufhören. Vergleichen Sie nach dem Tag Ihren Durchschnittspreis mit dem Markt-VWAP: Die Differenz in Basispunkten ist der Tracking Error des Algorithmus. Den VWAP zu schlagen, indem man spät in einem steigenden Markt handelt, ist keine Kunst; beurteilen Sie einen Algorithmus nach seinem Slippage über viele Tage.
# A participation cap: never more than a fraction of the market's volume, carrying the rest forward
import math
def cap_participation(schedule, market_volumes, rate):
trades, carry = [], 0
for scheduled, volume in zip(schedule, market_volumes):
wanted = scheduled + carry
done = min(wanted, math.floor(rate * volume + 1e-9))
trades.append(done)
carry = wanted - done
return trades, carry
print(cap_participation([100, 100, 100], [500, 1000, 1000], 0.1)) # ([50, 100, 100], 50)
print(cap_participation([100, 0, 0, 0], [500, 1000, 400, 800], 0.1)) # ([50, 50, 0, 0], 0) the carry is traded when the market allows it# Following the clock (TWAP) and following the volume (VWAP) give different average prices on the same day
prices = [100.0, 100.2, 100.1, 100.4, 100.3, 100.5]
volumes = [300, 100, 100, 200, 500, 800] # busy at the open and the close
market_vwap = sum(p * v for p, v in zip(prices, volumes)) / sum(volumes)
twap_average = sum(prices) / len(prices) # equal pieces at every time
print(round(market_vwap, 4), round(twap_average, 4)) # 100.33 100.25
print(round((twap_average - market_vwap) / market_vwap * 10000, 1)) # -8.0 a TWAP buy beat the VWAP here, by trading light when volume was heavy- VWAP ist
sum(price * volume) / sum(volume), der gängige Benchmark; ein VWAP-Algorithmus handelt proportional zum Marktvolumen. - Schätzen Sie ein Volumenprofil aus der Historie und teilen Sie die Order mit der Methode des größten Rests darauf auf, damit ganze Aktien exakt aufgehen.
- Deckeln Sie Ihre Beteiligung in jedem Intervall und tragen Sie den Rest vor; beurteilen Sie den Algorithmus nach Tracking Error und Slippage über viele Tage.
Als Nächstes: Market Making, beide Seiten quotieren und den entstehenden Bestand verwalten.
Lab: Was bewertet wird
- Den Benchmark mit
vwapberechnen25 Pkt. - Mit
volume_profileden Tag formen25 Pkt. - Die Order mit
vwap_scheduleaufteilen25 Pkt. - Den Markt mit
cap_participationrespektieren25 Pkt.