import json
import csv
from datetime import datetime, timedelta
import random
def generate_realistic_vwap_flow():
snapshots = []
record_id = 0
current_time = datetime.now().replace(hour=9, minute=30, second=0, microsecond=0)
market_price = 650.00
def add_snapshot(order, event_type, timestamp, market_price=None):
nonlocal record_id
snapshot = order.copy()
snapshot['snapshot_time'] = timestamp.isoformat()
snapshot['event_type'] = event_type
snapshot['record_id'] = f"REC_{record_id:08d}"
if market_price:
snapshot['market_price'] = market_price
snapshots.append(snapshot)
record_id += 1
return snapshot
client_order = {
'order_id': 'CLIENT_C20241216_100001',
'parent_order_id': None,
'client_order_id': 'C20241216_100001',
'order_level': 0,
'order_type': 'CLIENT',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': 50000,
'filled_quantity': 0,
'remaining_quantity': 50000,
'average_price': 0.0,
'state': 'PENDING',
'trader': 'TRD001',
'client_name': 'Blackrock'
}
add_snapshot(client_order, 'NEW', current_time, market_price)
current_time += timedelta(seconds=1)
client_order['state'] = 'ACCEPTED'
add_snapshot(client_order, 'ACCEPTED', current_time, market_price)
algo_parent = {
'order_id': 'ALGO_50001',
'parent_order_id': 'CLIENT_C20241216_100001',
'client_order_id': 'C20241216_100001',
'order_level': 1,
'order_type': 'ALGO_PARENT',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': 50000,
'filled_quantity': 0,
'remaining_quantity': 50000,
'average_price': 0.0,
'state': 'WORKING',
'algo_strategy': 'VWAP'
}
add_snapshot(algo_parent, 'NEW', current_time, market_price)
total_filled = 0
total_value = 0.0
slices = [
{'qty': 15000, 'scenario': 'normal'},
{'qty': 20000, 'scenario': 'fade_retry'},
{'qty': 15000, 'scenario': 'partial_fills'}
]
for slice_num, slice_config in enumerate(slices, 1):
current_time += timedelta(minutes=30)
market_price += random.uniform(-0.5, 0.5)
slice_order = {
'order_id': f'SLICE_{60000 + slice_num}',
'parent_order_id': 'ALGO_50001',
'client_order_id': 'C20241216_100001',
'order_level': 2,
'order_type': 'ALGO_SLICE',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': slice_config['qty'],
'filled_quantity': 0,
'remaining_quantity': slice_config['qty'],
'average_price': 0.0,
'state': 'PENDING'
}
add_snapshot(slice_order, 'NEW', current_time, market_price)
current_time += timedelta(milliseconds=10)
slice_order['state'] = 'ACCEPTED'
add_snapshot(slice_order, 'ACCEPTED', current_time, market_price)
slice_filled = 0
slice_value = 0
if slice_config['scenario'] == 'normal':
venues = [('NYSE', 5000), ('NASDAQ', 5000), ('ARCA', 5000)]
for venue, qty in venues:
current_time += timedelta(milliseconds=50)
sor_order = {
'order_id': f'SOR_{70000 + slice_num * 10 + venues.index((venue, qty))}',
'parent_order_id': slice_order['order_id'],
'client_order_id': 'C20241216_100001',
'order_level': 3,
'order_type': 'ROUTE',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': qty,
'filled_quantity': 0,
'remaining_quantity': qty,
'average_price': 0.0,
'state': 'PENDING',
'venue': venue,
'instruction': 'IOC'
}
add_snapshot(sor_order, 'NEW', current_time, market_price)
current_time += timedelta(milliseconds=20)
sor_order['state'] = 'ACCEPTED'
add_snapshot(sor_order, 'VENUE_ACCEPTED', current_time, market_price)
current_time += timedelta(milliseconds=random.randint(50, 150))
fill_price = market_price + random.uniform(-0.02, 0.05)
sor_order['filled_quantity'] = qty
sor_order['remaining_quantity'] = 0
sor_order['average_price'] = fill_price
sor_order['state'] = 'FILLED'
add_snapshot(sor_order, 'VENUE_FILLED', current_time, market_price)
slice_filled += qty
slice_value += qty * fill_price
elif slice_config['scenario'] == 'fade_retry':
venues_try1 = [('NYSE', 8000), ('NASDAQ', 8000), ('BATS', 4000)]
for venue, qty in venues_try1:
current_time += timedelta(milliseconds=50)
sor_order = {
'order_id': f'SOR_{71000 + venues_try1.index((venue, qty))}',
'parent_order_id': slice_order['order_id'],
'client_order_id': 'C20241216_100001',
'order_level': 3,
'order_type': 'ROUTE',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': qty,
'filled_quantity': 0,
'remaining_quantity': qty,
'average_price': 0.0,
'state': 'PENDING',
'venue': venue,
'instruction': 'EOE',
'attempt': 1
}
add_snapshot(sor_order, 'NEW', current_time, market_price)
if venue == 'NASDAQ':
current_time += timedelta(milliseconds=30)
sor_order['state'] = 'FADE'
sor_order['fade_reason'] = 'Liquidity taken by competitor'
add_snapshot(sor_order, 'VENUE_FADE', current_time, market_price)
print(f" ❌ FADE at {venue}: Lost {qty:,} shares")
elif venue == 'BATS':
current_time += timedelta(milliseconds=40)
partial_qty = 1500
fill_price = market_price + 0.02
sor_order['filled_quantity'] = partial_qty
sor_order['remaining_quantity'] = qty - partial_qty
sor_order['average_price'] = fill_price
sor_order['state'] = 'PARTIAL'
add_snapshot(sor_order, 'VENUE_PARTIAL', current_time, market_price)
slice_filled += partial_qty
slice_value += partial_qty * fill_price
print(f" ⚠️ PARTIAL at {venue}: {partial_qty:,}/{qty:,}")
else: current_time += timedelta(milliseconds=60)
fill_price = market_price + 0.01
sor_order['filled_quantity'] = qty
sor_order['remaining_quantity'] = 0
sor_order['average_price'] = fill_price
sor_order['state'] = 'FILLED'
add_snapshot(sor_order, 'VENUE_FILLED', current_time, market_price)
slice_filled += qty
slice_value += qty * fill_price
remaining = slice_config['qty'] - slice_filled
if remaining > 0:
current_time += timedelta(milliseconds=500)
print(f" 🔄 RETRY: {remaining:,} shares remaining")
retry_venues = [('DARK', remaining)]
for venue, qty in retry_venues:
sor_order = {
'order_id': f'SOR_{71100}',
'parent_order_id': slice_order['order_id'],
'client_order_id': 'C20241216_100001',
'order_level': 3,
'order_type': 'ROUTE',
'ticker': 'ASML.AS',
'side': 'Buy',
'quantity': qty,
'filled_quantity': 0,
'remaining_quantity': qty,
'average_price': 0.0,
'state': 'PENDING',
'venue': venue,
'instruction': 'IOC',
'attempt': 2
}
add_snapshot(sor_order, 'NEW_RETRY', current_time, market_price)
current_time += timedelta(milliseconds=100)
fill_price = market_price - 0.01 sor_order['filled_quantity'] = qty
sor_order['remaining_quantity'] = 0
sor_order['average_price'] = fill_price
sor_order['state'] = 'FILLED'
add_snapshot(sor_order, 'VENUE_FILLED', current_time, market_price)
slice_filled += qty
slice_value += qty * fill_price
current_time += timedelta(milliseconds=50)
slice_order['filled_quantity'] = slice_filled
slice_order['remaining_quantity'] = slice_config['qty'] - slice_filled
slice_order['average_price'] = slice_value / slice_filled if slice_filled > 0 else 0
slice_order['state'] = 'FILLED' if slice_filled >= slice_config['qty'] else 'PARTIAL'
add_snapshot(slice_order, 'SLICE_COMPLETE', current_time, market_price)
total_filled += slice_filled
total_value += slice_value
current_time += timedelta(milliseconds=10)
algo_parent['filled_quantity'] = total_filled
algo_parent['remaining_quantity'] = 50000 - total_filled
algo_parent['average_price'] = total_value / total_filled if total_filled > 0 else 0
algo_parent['state'] = 'FILLED' if total_filled >= 50000 else 'WORKING'
add_snapshot(algo_parent, 'ALGO_UPDATE', current_time, market_price)
current_time += timedelta(milliseconds=10)
client_order['filled_quantity'] = total_filled
client_order['remaining_quantity'] = 50000 - total_filled
client_order['average_price'] = algo_parent['average_price']
client_order['state'] = 'FILLED' if total_filled >= 50000 else 'WORKING'
add_snapshot(client_order, 'CLIENT_UPDATE', current_time, market_price)
with open('realistic_flow.json', 'w') as f:
json.dump(snapshots, f, indent=2, default=str)
if snapshots:
keys = set()
for s in snapshots:
keys.update(s.keys())
with open('realistic_flow.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=sorted(keys))
writer.writeheader()
writer.writerows(snapshots)
print(f"\n✅ Generated {len(snapshots)} snapshots")
print(f"📊 Final: {total_filled:,}/50,000 @ {total_value/total_filled:.2f}")
fade_events = [s for s in snapshots if s.get('event_type') == 'VENUE_FADE']
partial_events = [s for s in snapshots if s.get('event_type') == 'VENUE_PARTIAL']
retry_events = [s for s in snapshots if s.get('event_type') == 'NEW_RETRY']
print(f"\n📈 Events:")
print(f" Fades: {len(fade_events)}")
print(f" Partials: {len(partial_events)}")
print(f" Retries: {len(retry_events)}")
return snapshots
if __name__ == "__main__":
print("GENERATING REALISTIC VWAP FLOW WITH MICROSTRUCTURE ISSUES")
print("=" * 60)
generate_realistic_vwap_flow()