File size: 4,305 Bytes
fc3352e
19bb366
fc3352e
 
80ec238
fc3352e
80ec238
475d23a
fc3352e
08519ee
 
1327196
08519ee
56762b6
08519ee
1327196
 
 
 
 
475d23a
08519ee
1327196
fc3352e
08519ee
475d23a
 
 
 
 
08519ee
56762b6
08519ee
56762b6
08519ee
 
 
1327196
 
 
475d23a
1327196
475d23a
08519ee
 
475d23a
 
 
08519ee
 
 
56762b6
08519ee
 
1327196
08519ee
 
475d23a
 
fc3352e
08519ee
 
 
1327196
08519ee
00e57f5
56762b6
 
475d23a
08519ee
 
 
56762b6
 
475d23a
08519ee
 
 
 
 
 
c1fcb74
8e4dd54
475d23a
56762b6
08519ee
56762b6
08519ee
56762b6
 
8e4dd54
c1fcb74
08519ee
c1fcb74
56762b6
08519ee
1327196
45fc8df
56762b6
 
 
08519ee
45fc8df
08519ee
1327196
08519ee
45fc8df
1327196
8e4dd54
08519ee
45fc8df
08519ee
 
 
 
 
 
 
1327196
 
08519ee
 
45fc8df
 
08519ee
 
d431f8f
08519ee
8e4dd54
475d23a
8e4dd54
1327196
8e4dd54
 
475d23a
 
c1fcb74
1327196
d431f8f
56762b6
08519ee
 
 
 
 
 
 
19bb366
475d23a
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import yfinance as yf
import pandas as pd
import numpy as np
import mplfinance as mpf
import talib
import gradio as gr
import os
from datetime import date

# ---------------- TALib Patterns ----------------
TALIB_PATTERNS = sorted(p for p in dir(talib) if p.startswith("CDL"))
PATTERN_MAP = {p.replace("CDL", ""): p for p in TALIB_PATTERNS}
PATTERNS = ["None"] + list(PATTERN_MAP.keys())

# ---------------- Data Cleaning ----------------
def clean_ohlc(df):
    df = df.copy()

    if isinstance(df.columns, pd.MultiIndex):
        df.columns = df.columns.get_level_values(0)

    df.columns = [c.lower() for c in df.columns]
    df.index.name = None

    df = df.rename(columns={
        "open": "Open",
        "high": "High",
        "low": "Low",
        "close": "Close",
        "volume": "Volume"
    })

    df.index = pd.to_datetime(df.index, errors="coerce")

    for c in ["Open", "High", "Low", "Close", "Volume"]:
        if c in df.columns:
            df[c] = pd.to_numeric(df[c], errors="coerce")

    df = df.dropna(subset=["Open", "High", "Low", "Close"])
    df = df.sort_index()

    return df

# ---------------- Load Data ----------------
def load_data(symbol, start, end):
    if not symbol:
        return None, "❌ Symbol required"

    df = yf.download(symbol, start=start, end=end, progress=False)
    if df.empty:
        return None, "❌ No data found"

    df = clean_ohlc(df)
    return df, f"βœ… Loaded {len(df)} rows"

# ---------------- Pattern Builder ----------------
def build_pattern(df, pattern):
    if pattern == "None":
        return []

    func = getattr(talib, PATTERN_MAP[pattern])
    res = func(df["Open"], df["High"], df["Low"], df["Close"])
    s = pd.Series(res, index=df.index)

    aps = []

    if (s > 0).any():
        bull = pd.Series(np.nan, index=df.index)
        bull[s > 0] = df["Low"][s > 0] * 0.98
        aps.append(mpf.make_addplot(bull, type="scatter",
                                    marker="^", color="green", markersize=90))

    if (s < 0).any():
        bear = pd.Series(np.nan, index=df.index)
        bear[s < 0] = df["High"][s < 0] * 1.02
        aps.append(mpf.make_addplot(bear, type="scatter",
                                    marker="v", color="red", markersize=90))

    return aps

# ---------------- Build Chart ----------------
def build_chart(df, symbol, pattern):
    if df is None:
        return None, "❌ Load data first"

    addplots = build_pattern(df, pattern)
    os.makedirs("/tmp", exist_ok=True)
    path = f"/tmp/{symbol}_{pattern}.png"

    fig, _ = mpf.plot(
        df,
        type="candle",
        volume="Volume" in df.columns,
        addplot=addplots if addplots else None,
        style="yahoo",
        title=f"{symbol} | {pattern}",
        figscale=1.8,
        returnfig=True
    )

    fig.savefig(path, dpi=150, bbox_inches="tight")
    return path, "βœ… Chart rebuilt"

# ================= GRADIO APP =================
with gr.Blocks(fill_height=True) as app:
    gr.Markdown("## πŸ“Š Candlestick Pattern Analyzer")

    state_df = gr.State(None)

    # -------- Load Section --------
    with gr.Row():
        symbol = gr.Textbox(label="Symbol", value="MSFT")
        start = gr.Textbox(label="Start Date", value="2024-01-01")
        end = gr.Textbox(label="End Date", value=date.today().strftime("%Y-%m-%d"))
        load_btn = gr.Button("Load Data", variant="primary")
        load_status = gr.Textbox(label="Load Status")

    # -------- Pattern + Chart --------
    with gr.Row():
        with gr.Column(scale=1):
            pattern = gr.Dropdown(PATTERNS, value="None", label="Pattern")
            build_btn = gr.Button("Build Chart")

        with gr.Column(scale=3):
            chart = gr.Image(height=600)
            build_status = gr.Textbox(label="Status")

    # -------- Events --------
    load_btn.click(
        load_data,
        inputs=[symbol, start, end],
        outputs=[state_df, load_status]
    )

    build_btn.click(
        build_chart,
        inputs=[state_df, symbol, pattern],
        outputs=[chart, build_status]
    )

    # πŸ”₯ AUTO REBUILD WHEN PATTERN CHANGES
    pattern.change(
        build_chart,
        inputs=[state_df, symbol, pattern],
        outputs=[chart, build_status]
    )

if __name__ == "__main__":
    app.launch()