File size: 3,979 Bytes
ead14e8
 
 
 
b685ea7
 
 
 
 
 
 
 
 
 
ead14e8
b685ea7
 
 
 
 
 
 
 
 
 
 
 
 
ead14e8
b685ea7
 
ead14e8
b685ea7
 
 
 
ead14e8
b685ea7
ead14e8
b685ea7
 
 
 
 
 
 
 
 
 
ead14e8
b685ea7
 
 
 
 
 
 
 
ead14e8
b685ea7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ead14e8
 
b685ea7
 
ead14e8
 
 
b685ea7
 
ead14e8
b685ea7
 
 
 
 
ead14e8
 
b685ea7
 
ead14e8
b685ea7
ead14e8
b685ea7
 
ead14e8
b685ea7
ead14e8
b685ea7
ead14e8
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import gradio as gr
import random
import plotly.graph_objects as go

# We use a simple dict for state to keep Hugging Face happy
init_state = {
    "balance": 10000.0,
    "shares": 0,
    "avg_buy_price": 0.0,
    "stock_price": 100.0,
    "price_history": [100.0],
    "current_mode": "Sideways ➑️",
    "tick_counter": 0
}

def tick(state):
    state["tick_counter"] += 1
    
    # Change market modes
    if state["tick_counter"] % 15 == 0:
        state["current_mode"] = random.choice(["Bull πŸ“ˆ", "Bear πŸ“‰", "Sideways ➑️"])
    
    # Percentage calculation
    base_move = random.uniform(-0.03, 0.03)
    if state["current_mode"] == "Bull πŸ“ˆ":
        base_move += random.uniform(0.005, 0.02)
    elif state["current_mode"] == "Bear πŸ“‰":
        base_move -= random.uniform(0.005, 0.02)
        
    if random.random() < 0.02: # Black swan
        base_move += random.choice([-0.08, 0.08])
        
    state["stock_price"] = max(1.0, round(state["stock_price"] * (1 + base_move), 2))
    state["price_history"].append(state["stock_price"])
    if len(state["price_history"]) > 30:
        state["price_history"].pop(0)
        
    return state, *get_ui_updates(state)

def buy_stock(state):
    if state["balance"] >= state["stock_price"]:
        shares_to_buy = min(10, int(state["balance"] // state["stock_price"]))
        if shares_to_buy > 0:
            total_cost = shares_to_buy * state["stock_price"]
            total_shares = state["shares"] + shares_to_buy
            state["avg_buy_price"] = ((state["shares"] * state["avg_buy_price"]) + total_cost) / total_shares
            state["shares"] = total_shares
            state["balance"] -= total_cost
    return state, *get_ui_updates(state)

def sell_stock(state):
    if state["shares"] > 0:
        shares_to_sell = min(10, state["shares"])
        state["balance"] += shares_to_sell * state["stock_price"]
        state["shares"] -= shares_to_sell
        if state["shares"] == 0:
            state["avg_buy_price"] = 0.0
    return state, *get_ui_updates(state)

def get_ui_updates(state):
    pnl = (state["shares"] * state["stock_price"]) - (state["shares"] * state["avg_buy_price"])
    pnl_str = f"+${pnl:,.2f}" if pnl >= 0 else f"-${abs(pnl):,.2f}"
    net_worth = state["balance"] + (state["shares"] * state["stock_price"])
    
    fig = go.Figure()
    fig.add_trace(go.Scatter(y=state["price_history"], mode='lines+markers', line=dict(color='#2196F3', width=3)))
    fig.update_layout(template="plotly_dark", margin=dict(l=10, r=10, t=10, b=10), height=300)
    
    return (
        f"${state['balance']:,.2f}",
        f"${state['stock_price']:,.2f}",
        str(state["shares"]),
        f"${state['avg_buy_price']:,.2f}",
        pnl_str,
        f"${net_worth:,.2f}",
        f"Market: {state['current_mode']}",
        fig
    )

with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# πŸ“ˆ StockSim")
    state = gr.State(default=init_state.copy())
    
    with gr.Row():
        with gr.Column(scale=2):
            chart = gr.Plot()
            regime_display = gr.Markdown("Market: Sideways ➑️")
        with gr.Column(scale=1):
            net_worth_box = gr.Textbox(label="Net Worth")
            balance_box = gr.Textbox(label="Cash")
            shares_box = gr.Textbox(label="Shares")
            avg_box = gr.Textbox(label="Avg Cost")
            pnl_box = gr.Textbox(label="P&L")

    with gr.Row():
        btn_buy = gr.Button("BUY 10", variant="primary")
        btn_sell = gr.Button("SELL 10", variant="secondary")

    outputs = [balance_box, gr.Textbox(visible=False), shares_box, avg_box, pnl_box, net_worth_box, regime_display, chart]
    
    btn_buy.click(buy_stock, inputs=[state], outputs=[state] + outputs)
    btn_sell.click(sell_stock, inputs=[state], outputs=[state] + outputs)
    
    # Timer updates state explicitly
    timer = gr.Timer(1.0)
    timer.tick(tick, inputs=[state], outputs=[state] + outputs)

demo.launch()