kosmoscpp commited on
Commit
ead14e8
Β·
verified Β·
1 Parent(s): 06dc1a6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -0
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import random
3
+ import pandas as pd
4
+ import plotly.graph_objects as go
5
+
6
+ # --- SIMULATION STATE ---
7
+ class MarketSimulation:
8
+ def __init__(self):
9
+ self.reset()
10
+
11
+ def reset(self):
12
+ self.balance = 10000.0
13
+ self.shares = 0
14
+ self.avg_buy_price = 0.0
15
+ self.stock_price = 100.0
16
+ self.price_history = [100.0]
17
+ self.market_modes = ["Bull πŸ“ˆ", "Bear πŸ“‰", "Sideways ➑️"]
18
+ self.current_mode = "Sideways ➑️"
19
+ self.tick_counter = 0
20
+
21
+ def tick(self):
22
+ self.tick_counter += 1
23
+
24
+ # V2: Shift market regimes every 15 seconds
25
+ if self.tick_counter % 15 == 0:
26
+ self.current_mode = random.choice(self.market_modes)
27
+
28
+ # Base volatility (percentage-based)
29
+ base_move = random.uniform(-0.03, 0.03) # Β±3%
30
+
31
+ # Apply regime bias
32
+ if self.current_mode == "Bull πŸ“ˆ":
33
+ base_move += random.uniform(0.005, 0.02) # Upward bias
34
+ elif self.current_mode == "Bear πŸ“‰":
35
+ base_move -= random.uniform(0.005, 0.02) # Downward bias
36
+
37
+ # Occasional "Black Swan" shock move (2% chance)
38
+ if random.random() < 0.02:
39
+ base_move += random.choice([-0.08, 0.08]) # Sudden Β±8% spike
40
+
41
+ # Calculate new price
42
+ self.stock_price = max(1.0, round(self.stock_price * (1 + base_move), 2))
43
+ self.price_history.append(self.stock_price)
44
+
45
+ # Keep history manageable
46
+ if len(self.price_history) > 40:
47
+ self.price_history.pop(0)
48
+
49
+ return self.get_status(), self.update_chart()
50
+
51
+ def buy_stock(self):
52
+ if self.balance >= self.stock_price:
53
+ # Buy max possible shares for simplicity, or just 10 shares
54
+ shares_to_buy = min(10, int(self.balance // self.stock_price))
55
+ if shares_to_buy > 0:
56
+ total_cost = shares_to_buy * self.stock_price
57
+
58
+ # Recalculate average buy price
59
+ total_shares = self.shares + shares_to_buy
60
+ self.avg_buy_price = ((self.shares * self.avg_buy_price) + total_cost) / total_shares
61
+
62
+ self.shares += shares_to_buy
63
+ self.balance -= total_cost
64
+ return self.get_status(), self.update_chart()
65
+
66
+ def sell_stock(self):
67
+ if self.shares > 0:
68
+ shares_to_sell = min(10, self.shares)
69
+ total_revenue = shares_to_sell * self.stock_price
70
+ self.shares -= shares_to_sell
71
+ self.balance += total_revenue
72
+ if self.shares == 0:
73
+ self.avg_buy_price = 0.0
74
+ return self.get_status(), self.update_chart()
75
+
76
+ def get_status(self):
77
+ # Calculate Profit/Loss
78
+ current_value = self.shares * self.stock_price
79
+ cost_basis = self.shares * self.avg_buy_price
80
+ pnl = current_value - cost_basis
81
+ pnl_string = f"+${pnl:,.2f}" if pnl >= 0 else f"-${abs(pnl):,.2f}"
82
+
83
+ portfolio_value = self.balance + current_value
84
+
85
+ return (
86
+ f"${self.balance:,.2f}",
87
+ f"${self.stock_price:,.2f}",
88
+ f"{self.shares}",
89
+ f"${self.avg_buy_price:,.2f}",
90
+ pnl_string,
91
+ f"${portfolio_value:,.2f}",
92
+ f"Current Regime: {self.current_mode}"
93
+ )
94
+
95
+ def update_chart(self):
96
+ fig = go.Figure()
97
+ fig.add_trace(go.Scatter(
98
+ y=self.price_history,
99
+ mode='lines+markers',
100
+ line=dict(color='#2196F3', width=3),
101
+ marker=dict(size=6),
102
+ name='Price'
103
+ ))
104
+ fig.update_layout(
105
+ title="Live Stock Price (Updates Every Second)",
106
+ xaxis_title="Time (Ticks)",
107
+ yaxis_title="Price ($)",
108
+ template="plotly_dark",
109
+ margin=dict(l=20, r=20, t=40, b=20),
110
+ height=350
111
+ )
112
+ return fig
113
+
114
+ # --- GRADIO INTERFACE ---
115
+ sim = MarketSimulation()
116
+
117
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
118
+ gr.Markdown("# πŸ“ˆ PaperTrader Sim V2")
119
+ gr.Markdown("A pure-Python live market sandbox. Watch out for regime shifts and black swan shocks!")
120
+
121
+ with gr.Row():
122
+ with gr.Column(scale=2):
123
+ chart = gr.Plot(value=sim.update_chart())
124
+ regime_display = gr.Markdown("Current Regime: Sideways ➑️")
125
+
126
+ with gr.Column(scale=1):
127
+ gr.Markdown("### πŸ’° Account & Portfolio")
128
+ total_net_worth = gr.Textbox(label="Total Net Worth", value="$10,000.00", interactive=False)
129
+ balance_box = gr.Textbox(label="Cash Balance", value="$10,000.00", interactive=False)
130
+ shares_box = gr.Textbox(label="Shares Owned", value="0", interactive=False)
131
+ avg_price_box = gr.Textbox(label="Avg Buy Price", value="$0.00", interactive=False)
132
+ pnl_box = gr.Textbox(label="Profit / Loss", value="$0.00", interactive=False)
133
+
134
+ with gr.Row():
135
+ btn_buy = gr.Button("πŸ›’ BUY 10 SHARES", variant="primary")
136
+ btn_sell = gr.Button("πŸ’΅ SELL 10 SHARES", variant="secondary")
137
+ btn_reset = gr.Button("πŸ”„ Reset Simulation")
138
+
139
+ # Connect UI Components
140
+ status_outputs = [balance_box, gr.Textbox(visible=False), shares_box, avg_price_box, pnl_box, total_net_worth, regime_display]
141
+
142
+ btn_buy.click(sim.buy_stock, outputs=[status_outputs[0], status_outputs[2], status_outputs[3], status_outputs[4], status_outputs[5], status_outputs[6], chart])
143
+ btn_sell.click(sim.sell_stock, outputs=[status_outputs[0], status_outputs[2], status_outputs[3], status_outputs[4], status_outputs[5], status_outputs[6], chart])
144
+
145
+ def reset_ui():
146
+ sim.reset()
147
+ return sim.get_status() + (sim.update_chart(),)
148
+
149
+ btn_reset.click(reset_ui, outputs=[balance_box, gr.Textbox(visible=False), shares_box, avg_price_box, pnl_box, total_net_worth, regime_display, chart])
150
+
151
+ # The magic engine: Trigger a tick every 1.0 second automatically
152
+ timer = gr.Timer(1.0)
153
+ timer.tick(sim.tick, outputs=[balance_box, gr.Textbox(visible=False), shares_box, avg_price_box, pnl_box, total_net_worth, regime_display, chart])
154
+
155
+ demo.launch()