DOGE $1 in 2025? Whale Accumulation + Forecast with Python GUI | FuzzuTech
Demo :
Click Video πππ
Description:
Is Dogecoin hitting $1 in 2025? π Explore this Python + CTkinter GUI app for DOGE price analysis, whale accumulation index & Monte Carlo forecasts.
Features:
-
Embedded YouTube Short
-
Code snippet (GitHub link if you want)
-
Screenshots from GUI (charts, whale proxy, forecast)
-
SEO keywords: Dogecoin price forecast 2025, DOGE $1, Python crypto app, whale accumulation index, Monte Carlo crypto simulation
Code :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FuzzuTech — DOGE $1 in 2025? (Python + CTkinter GUI)
Single-file modern app to visualize DOGE price, compute a simple Whale Accumulation Proxy,
run Monte‑Carlo forecasts, and generate a bull/bear/base report.
Dependencies (install as needed):
pip install customtkinter matplotlib requests numpy pandas
Optional (improves fonts on Windows):
pip install pillow
Notes:
- Uses public CoinGecko endpoints (no API key). If the API is down, app falls back to cached sample.
- Whale Accumulation Proxy (WAP) is a heuristic based on: high volume on red days + low volatility clustering.
It is NOT on-chain whale tracking. Treat as an educational indicator.
"""
import os
import sys
import json
import math
import time
import datetime as dt
from dataclasses import dataclass
from typing import List, Tuple, Optional
# UI
try:
import customtkinter as ctk
except Exception as e:
print("Please install customtkinter: pip install customtkinter")
raise
import threading
import requests
import numpy as np
try:
import pandas as pd
except Exception:
pd = None
import matplotlib
matplotlib.use("Agg") # render offscreen for thread-safety
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
APP_NAME = "FuzzuTech — DOGE $1?"
COINGECKO_BASE = "https://api.coingecko.com/api/v3"
# --------------------------- Data Layer ---------------------------- #
@dataclass
class MarketPoint:
time: dt.datetime
price: float
volume: float
@dataclass
class MarketSnapshot:
now_price: float
change_24h: float
market_cap: Optional[float]
last_updated: dt.datetime
class DogeData:
def __init__(self):
self.history: List[MarketPoint] = []
self.snapshot: Optional[MarketSnapshot] = None
def fetch_snapshot(self) -> MarketSnapshot:
url = f"{COINGECKO_BASE}/simple/price?ids=dogecoin&vs_currencies=usd&include_24hr_change=true&include_market_cap=true&precision=6"
r = requests.get(url, timeout=15)
r.raise_for_status()
d = r.json()["dogecoin"]
snap = MarketSnapshot(
now_price=float(d.get("usd", np.nan)),
change_24h=float(d.get("usd_24h_change", np.nan)),
market_cap=float(d.get("usd_market_cap", np.nan)),
last_updated=dt.datetime.utcnow(),
)
self.snapshot = snap
return snap
def fetch_history(self, days: int = 365) -> List[MarketPoint]:
url = f"{COINGECKO_BASE}/coins/dogecoin/market_chart?vs_currency=usd&days={days}&interval=daily"
r = requests.get(url, timeout=20)
r.raise_for_status()
data = r.json()
prices = data.get("prices", [])
vols = data.get("total_volumes", [])
out: List[MarketPoint] = []
for (t, p), (_, v) in zip(prices, vols):
out.append(MarketPoint(time=dt.datetime.utcfromtimestamp(t/1000.0), price=float(p), volume=float(v)))
self.history = out
return out
def ensure_data(self):
try:
if not self.snapshot:
self.fetch_snapshot()
if not self.history:
self.fetch_history(365)
except Exception:
# Fallback to tiny sample so UI still loads
now = dt.datetime.utcnow()
self.snapshot = MarketSnapshot(0.065, -1.2, 9200000000.0, now)
self.history = [
MarketPoint(now - dt.timedelta(days=i), 0.05 + 0.0002*i + 0.005*np.sin(i/7), 1e9+5e7*np.sin(i/3))
for i in range(365, -1, -1)
]
# ------------------------ Indicators & Models ---------------------- #
def to_series(history: List[MarketPoint]):
"""Return numpy arrays (dates, prices, volumes)."""
dates = np.array([mp.time for mp in history])
prices = np.array([mp.price for mp in history], dtype=float)
vols = np.array([mp.volume for mp in history], dtype=float)
return dates, prices, vols
def moving_average(x: np.ndarray, n: int) -> np.ndarray:
if n <= 1:
return x.copy()
kern = np.ones(n)/n
return np.convolve(x, kern, mode='same')
def bollinger_bands(x: np.ndarray, n: int = 20, k: float = 2.0) -> Tuple[np.ndarray, np.ndarray]:
ma = moving_average(x, n)
# rolling std (simple)
pad = n//2
std = np.array([np.std(x[max(0,i-pad):min(len(x), i+pad+1)]) for i in range(len(x))])
upper = ma + k*std
lower = ma - k*std
return upper, lower
def whale_accumulation_proxy(prices: np.ndarray, volumes: np.ndarray, lookback: int = 30) -> Tuple[float, dict]:
"""
Heuristic index in [0, 100]. Higher implies more likely silent accumulation.
Components:
- High Volume Red Days: days where close<prev_close and volume>median -> suspected stealth buying via sell pressure absorption.
- Low Volatility Clusters: std of returns below 30d median suggests quiet accumulation periods.
- Rising OBV: simple On-Balance Volume slope over lookback.
"""
if len(prices) < lookback + 5:
return 50.0, {"note": "insufficient history"}
rets = np.diff(np.log(prices))
vol_med = np.median(volumes[-lookback:])
red_days = 0
for i in range(1, lookback+1):
if prices[-i] < prices[-i-1] and volumes[-i] > vol_med:
red_days += 1
red_score = min(1.0, red_days / (lookback*0.5)) # saturate
# low vol cluster
rolling_std = np.array([np.std(rets[max(0,i-lookback):i+1]) for i in range(len(rets))])
lowvol = 1.0 - (np.mean(rolling_std[-lookback:]) / (np.median(rolling_std[-lookback:]) + 1e-9))
lowvol = float(np.clip(0.5 + 0.5*lowvol, 0, 1))
# OBV slope
obv = [0.0]
for i in range(1, len(prices)):
obv.append(obv[-1] + (volumes[i] if prices[i] > prices[i-1] else (-volumes[i] if prices[i] < prices[i-1] else 0)))
obv = np.array(obv)
x = np.arange(len(obv))
# simple slope via last lookback points
xb = x[-lookback:]
yb = obv[-lookback:]
denom = (len(xb)*np.sum(xb**2) - (np.sum(xb))**2) + 1e-9
slope = (len(xb)*np.sum(xb*yb) - np.sum(xb)*np.sum(yb)) / denom
slope_norm = 0.5 + 0.5*np.tanh(slope / (np.std(yb)+1e-9))
# combine
score = 100.0 * (0.45*red_score + 0.35*lowvol + 0.20*slope_norm)
detail = {
"red_days": int(red_days),
"red_score": float(red_score),
"lowvol_component": float(lowvol),
"obv_slope_component": float(slope_norm)
}
return float(np.clip(score, 0, 100)), detail
def gbm_forecast(prices: np.ndarray, days: int = 180, n_paths: int = 500,
drift_adj: float = 0.0, vol_adj: float = 1.0, seed: Optional[int] = 42) -> np.ndarray:
"""Geometric Brownian Motion simulation returning paths [n_paths, days+1]."""
if seed is not None:
np.random.seed(seed)
last = prices[-1]
logrets = np.diff(np.log(prices))
mu = np.mean(logrets) + drift_adj
sigma = np.std(logrets) * vol_adj
dtau = 1.0
paths = np.zeros((n_paths, days+1))
paths[:,0] = last
for t in range(1, days+1):
z = np.random.normal(size=n_paths)
paths[:,t] = paths[:,t-1] * np.exp((mu - 0.5*sigma**2)*dtau + sigma*np.sqrt(dtau)*z)
return paths
# --------------------------- UI Components ------------------------- #
class DogeApp(ctk.CTk):
def __init__(self):
super().__init__()
ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue")
self.geometry("1100x720")
self.title(APP_NAME)
self.minsize(1000, 650)
self.data = DogeData()
# State vars
self.etf_positive = ctk.BooleanVar(value=False)
self.user_sentiment = ctk.DoubleVar(value=0.0) # -1..+1
self.forecast_days = ctk.IntVar(value=180)
self.paths_var = ctk.IntVar(value=500)
self.lookback_var = ctk.IntVar(value=30)
# Layout
self._build_layout()
self._async_refresh()
# ---- Layout helpers ---- #
def _build_layout(self):
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
# Sidebar
sidebar = ctk.CTkFrame(self, corner_radius=16)
sidebar.grid(row=0, column=0, sticky="nsw", padx=12, pady=12)
sidebar.grid_rowconfigure(10, weight=1)
ctk.CTkLabel(sidebar, text="DOGE $1?", font=("Segoe UI", 22, "bold")).grid(row=0, column=0, padx=12, pady=(12,6))
self.price_lbl = ctk.CTkLabel(sidebar, text="Price: —", font=("Segoe UI", 16))
self.price_lbl.grid(row=1, column=0, padx=12, pady=4)
self.chg_lbl = ctk.CTkLabel(sidebar, text="24h: —", font=("Segoe UI", 14))
self.chg_lbl.grid(row=2, column=0, padx=12, pady=2)
self.mc_lbl = ctk.CTkLabel(sidebar, text="MCap: —", font=("Segoe UI", 13))
self.mc_lbl.grid(row=3, column=0, padx=12, pady=2)
ctk.CTkButton(sidebar, text="Refresh Data", command=self._async_refresh).grid(row=4, column=0, padx=12, pady=(10,4))
ctk.CTkButton(sidebar, text="Run Forecast", command=self._run_forecast).grid(row=5, column=0, padx=12, pady=4)
ctk.CTkButton(sidebar, text="Export Report", command=self._export_report).grid(row=6, column=0, padx=12, pady=4)
ctk.CTkSwitch(sidebar, text="ETF Catalyst Positive", variable=self.etf_positive).grid(row=7, column=0, padx=12, pady=(12,6))
ctk.CTkLabel(sidebar, text="Your Sentiment (-1..+1)").grid(row=8, column=0, padx=12, pady=(10,2))
self.sent_scale = ctk.CTkSlider(sidebar, from_=-1.0, to=1.0, number_of_steps=40, variable=self.user_sentiment)
self.sent_scale.grid(row=9, column=0, padx=12, pady=6)
self.theme_btn = ctk.CTkSegmentedButton(sidebar, values=["Dark","Light"], command=self._toggle_theme)
self.theme_btn.set("Dark")
self.theme_btn.grid(row=11, column=0, padx=12, pady=(20,12))
# Main area with tabs
main = ctk.CTkTabview(self, corner_radius=16)
main.grid(row=0, column=1, sticky="nsew", padx=12, pady=12)
self.tab_chart = main.add("Chart")
self.tab_whale = main.add("Whale Index")
self.tab_fore = main.add("Forecast")
self.tab_notes = main.add("Notes & News")
self.tab_about = main.add("About")
# Chart tab
self.fig_chart = Figure(figsize=(6,4), dpi=120)
self.ax_price = self.fig_chart.add_subplot(111)
self.canvas_chart = FigureCanvasTkAgg(self.fig_chart, master=self.tab_chart)
self.canvas_chart.get_tk_widget().pack(fill="both", expand=True, padx=8, pady=8)
# Whale tab
whale_frame = ctk.CTkFrame(self.tab_whale)
whale_frame.pack(fill="both", expand=True, padx=8, pady=8)
whale_frame.grid_columnconfigure(1, weight=1)
ctk.CTkLabel(whale_frame, text="Lookback days:").grid(row=0, column=0, sticky="w", padx=8, pady=8)
ctk.CTkEntry(whale_frame, textvariable=self.lookback_var, width=80).grid(row=0, column=1, sticky="w")
ctk.CTkButton(whale_frame, text="Recompute", command=self._update_whale).grid(row=0, column=2, padx=8)
self.whale_lbl = ctk.CTkLabel(whale_frame, text="Whale Accumulation Proxy: —", font=("Segoe UI", 16, "bold"))
self.whale_lbl.grid(row=1, column=0, columnspan=3, sticky="w", padx=8, pady=(8,2))
self.whale_detail = ctk.CTkTextbox(whale_frame, height=120)
self.whale_detail.grid(row=2, column=0, columnspan=3, sticky="nsew", padx=8, pady=8)
whale_frame.grid_rowconfigure(2, weight=1)
# Forecast tab
fore_frame = ctk.CTkFrame(self.tab_fore)
fore_frame.pack(fill="both", expand=True, padx=8, pady=8)
for i in range(10):
fore_frame.grid_columnconfigure(i, weight=1)
ctk.CTkLabel(fore_frame, text="Days").grid(row=0, column=0, padx=6, pady=6)
ctk.CTkEntry(fore_frame, textvariable=self.forecast_days, width=80).grid(row=0, column=1)
ctk.CTkLabel(fore_frame, text="# Paths").grid(row=0, column=2)
ctk.CTkEntry(fore_frame, textvariable=self.paths_var, width=80).grid(row=0, column=3)
ctk.CTkButton(fore_frame, text="Simulate", command=self._run_forecast).grid(row=0, column=4, padx=6)
self.fig_fore = Figure(figsize=(6,4), dpi=120)
self.ax_fore = self.fig_fore.add_subplot(111)
self.canvas_fore = FigureCanvasTkAgg(self.fig_fore, master=fore_frame)
self.canvas_fore.get_tk_widget().grid(row=1, column=0, columnspan=10, sticky="nsew", padx=8, pady=8)
fore_frame.grid_rowconfigure(1, weight=1)
# Notes/News tab
self.notes = ctk.CTkTextbox(self.tab_notes)
self.notes.pack(fill="both", expand=True, padx=8, pady=8)
self.notes.insert("1.0", "Paste headlines/catalysts here. Set 'ETF Catalyst Positive' if relevant.\n\n")
# About tab
about = ctk.CTkLabel(self.tab_about, justify="left",
text=("FuzzuTech — DOGE Long‑Term Bull Case GUI\n\n"
"⚠️ Disclaimer: This app is educational. Forecasts are models, not financial advice.\n"
"Data: CoinGecko markets chart + simple heuristics for accumulation proxy."))
about.pack(anchor="w", padx=12, pady=12)
# ---- Actions ---- #
def _toggle_theme(self, value: str):
ctk.set_appearance_mode("dark" if value=="Dark" else "light")
def _async_refresh(self):
threading.Thread(target=self._refresh_data, daemon=True).start()
def _refresh_data(self):
self._set_status("Refreshing…")
try:
self.data.ensure_data()
# if online, refresh live
try:
self.data.fetch_snapshot()
self.data.fetch_history(365)
except Exception:
pass
self._update_sidebar()
self._draw_chart()
self._update_whale()
self._set_status("Ready")
except Exception as e:
self._set_status(f"Error: {e}")
def _set_status(self, msg: str):
self.title(f"{APP_NAME} — {msg}")
def _fmt_cur(self, x: float) -> str:
if x is None or math.isnan(x):
return "—"
# compact USD
absx = abs(x)
if absx >= 1e12:
s = f"${x/1e12:.2f}T"
elif absx >= 1e9:
s = f"${x/1e9:.2f}B"
elif absx >= 1e6:
s = f"${x/1e6:.2f}M"
elif absx >= 1e3:
s = f"${x/1e3:.2f}K"
else:
s = f"${x:.4f}"
return s
def _update_sidebar(self):
snap = self.data.snapshot
if not snap:
return
self.price_lbl.configure(text=f"Price: ${snap.now_price:.6f}")
chg = snap.change_24h
sign = "▲" if chg>=0 else "▼"
self.chg_lbl.configure(text=f"24h: {sign}{abs(chg):.2f}%")
self.mc_lbl.configure(text=f"MCap: {self._fmt_cur(snap.market_cap)}")
def _draw_chart(self):
dates, prices, vols = to_series(self.data.history)
self.ax_price.clear()
self.ax_price.plot(dates, prices, linewidth=1.6, label="Price")
ma20 = moving_average(prices, 20)
ma50 = moving_average(prices, 50)
ma200 = moving_average(prices, 200)
self.ax_price.plot(dates, ma20, linewidth=1.2, label="MA20")
self.ax_price.plot(dates, ma50, linewidth=1.2, label="MA50")
self.ax_price.plot(dates, ma200, linewidth=1.2, label="MA200")
u,l = bollinger_bands(prices, 20, 2.0)
self.ax_price.fill_between(dates, l, u, alpha=0.12, label="Bollinger 20/2")
self.ax_price.axhline(1.0, linestyle='--', linewidth=1.0, alpha=0.7, label="$1 target")
self.ax_price.set_title("DOGE/USD — Price with MAs & Bands")
self.ax_price.set_xlabel("Date")
self.ax_price.set_ylabel("USD")
self.ax_price.legend(loc="upper left")
self.fig_chart.tight_layout()
self._blit(self.canvas_chart)
def _blit(self, canvas):
# switch backend for draw then embed; keep Agg
canvas.draw()
def _update_whale(self):
_, prices, vols = to_series(self.data.history)
lb = max(10, int(self.lookback_var.get()))
score, detail = whale_accumulation_proxy(prices, vols, lookback=lb)
self.whale_lbl.configure(text=f"Whale Accumulation Proxy (last {lb}d): {score:.1f}/100")
pretty = json.dumps(detail, indent=2)
self.whale_detail.delete("1.0", "end")
self.whale_detail.insert("1.0", pretty)
def _run_forecast(self):
dates, prices, _ = to_series(self.data.history)
days = max(30, int(self.forecast_days.get()))
paths_n = max(100, int(self.paths_var.get()))
drift_adj = 0.0
# tweak drift by user sentiment and ETF toggle
drift_adj += 0.3 * float(self.user_sentiment.get()) / 365.0
if self.etf_positive.get():
drift_adj += 0.2 / 365.0
paths = gbm_forecast(prices, days=days, n_paths=paths_n, drift_adj=drift_adj)
p5 = np.percentile(paths, 5, axis=0)
p50 = np.percentile(paths, 50, axis=0)
p95 = np.percentile(paths, 95, axis=0)
self.ax_fore.clear()
horizon = np.arange(len(p50))
self.ax_fore.plot(horizon, p50, linewidth=1.8, label="Median")
self.ax_fore.fill_between(horizon, p5, p95, alpha=0.18, label="90% band")
self.ax_fore.axhline(1.0, linestyle='--', linewidth=1.0, alpha=0.7, label="$1 target")
self.ax_fore.set_title(f"GBM Forecast — {days} days | SentAdj={float(self.user_sentiment.get()):+.2f} ETF+={self.etf_positive.get()}")
self.ax_fore.set_xlabel("Days ahead")
self.ax_fore.set_ylabel("USD")
self.ax_fore.legend(loc="upper left")
self.fig_fore.tight_layout()
self._blit(self.canvas_fore)
def _export_report(self):
dates, prices, vols = to_series(self.data.history)
lb = max(10, int(self.lookback_var.get()))
wap, detail = whale_accumulation_proxy(prices, vols, lookback=lb)
days = max(30, int(self.forecast_days.get()))
paths = gbm_forecast(prices, days=days, n_paths=500,
drift_adj=(0.3 * float(self.user_sentiment.get()) / 365.0) + (0.2/365.0 if self.etf_positive.get() else 0.0))
p5 = np.percentile(paths, 5, axis=0)[-1]
p50 = np.percentile(paths, 50, axis=0)[-1]
p95 = np.percentile(paths, 95, axis=0)[-1]
snap = self.data.snapshot
price_now = snap.now_price if snap else prices[-1]
lines = []
lines.append(f"# FuzzuTech — DOGE Long‑Term Bull Case Report\n")
lines.append(f"Generated: {dt.datetime.utcnow().isoformat()}Z\n")
lines.append(f"Current Price: ${price_now:.6f}\n")
if snap:
lines.append(f"24h Change: {snap.change_24h:+.2f}%\n")
if snap.market_cap:
lines.append(f"Market Cap: {self._fmt_cur(snap.market_cap)}\n")
lines.append("\n## Whale Accumulation Proxy\n")
lines.append(f"Score (last {lb}d): {wap:.1f}/100\n")
lines.append("Details:\n\n")
lines.append(json.dumps(detail, indent=2))
lines.append("\n\n## Forecast Summary\n")
lines.append(f"Horizon: {days} days\n")
lines.append(f"Median: ${p50:.4f}\n")
lines.append(f"5th pct: ${p5:.4f}\n")
lines.append(f"95th pct: ${p95:.4f}\n")
lines.append(f"$1 target hit in median? {'YES' if p50>=1.0 else 'NO'}\n")
lines.append("\n## Catalysts / Notes (user-entered)\n")
lines.append(self.notes.get("1.0","end").strip() or "—")
os.makedirs("reports", exist_ok=True)
fname = os.path.join("reports", f"doge_bull_case_{int(time.time())}.md")
with open(fname, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
self._toast(f"Exported: {fname}")
def _toast(self, msg: str, dur_ms: int = 2000):
toast = ctk.CTkToplevel(self)
toast.geometry("320x60")
toast.title("")
toast.attributes("-topmost", True)
toast.overrideredirect(True)
ctk.CTkLabel(toast, text=msg, font=("Segoe UI", 12)).pack(expand=True, fill="both", padx=12, pady=12)
self.after(dur_ms, toast.destroy)
if __name__ == "__main__":
app = DogeApp()
app.mainloop()
Comments
Post a Comment