Add detailed PnL and duration stats to dashboard

This commit is contained in:
jackyu66git
2026-05-03 21:03:40 +08:00
parent a89a1f6cd8
commit 1e4a3f3b37
6 changed files with 177 additions and 10 deletions
+77 -10
View File
@@ -1,10 +1,13 @@
package main
import (
"encoding/json"
"os"
"strconv"
)
// Config holds all system configuration.
// Priority: .env vars > config.json > code defaults.
type Config struct {
TelegramBotToken string
TelegramChatID string
@@ -14,7 +17,7 @@ type Config struct {
// Automated trading
TradeEnabled bool
TradeThreshold float64 // minimum profit % to execute trade (>0.15%)
TradeThreshold float64 // minimum profit % to execute trade
TradeAmountUSD float64 // amount per trade in USDT
TradeCooldownMs int // ms between trades of same coin
@@ -32,7 +35,24 @@ type Config struct {
HLAddress string // wallet address
}
// jsonConfig maps config.json fields (non-secret defaults checked into git).
type jsonConfig struct {
TestMode bool `json:"test_mode"`
TradeEnabled bool `json:"trade_enabled"`
ArbThreshold float64 `json:"arb_threshold"`
ScanIntervalMs int `json:"scan_interval_ms"`
TradeThreshold float64 `json:"trade_threshold"`
TradeAmountUSD float64 `json:"trade_amount_usd"`
TradeCooldownMs int `json:"trade_cooldown_ms"`
AlertCooldownSec int `json:"alert_cooldown_sec"`
MockSlippagePct float64 `json:"mock_slippage_pct"`
}
func LoadConfig() *Config {
// 1. Load config.json defaults
jsonCfg := loadJSONConfig()
// 2. .env vars override config.json
getEnv := func(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
@@ -61,17 +81,17 @@ func LoadConfig() *Config {
return &Config{
TelegramBotToken: getEnv("TELEGRAM_BOT_TOKEN", ""),
TelegramChatID: getEnv("TELEGRAM_CHAT_ID", ""),
AlertCooldownSec: 300,
ArbThreshold: 0.03,
ScanIntervalMs: int(getFloat("SCAN_INTERVAL_MS", 500)),
AlertCooldownSec: int(getFloat("ALERT_COOLDOWN_SEC", float64(jsonCfg.AlertCooldownSec))),
ArbThreshold: getFloat("ARB_THRESHOLD", jsonCfg.ArbThreshold),
ScanIntervalMs: int(getFloat("SCAN_INTERVAL_MS", float64(jsonCfg.ScanIntervalMs))),
TradeEnabled: getBool("TRADE_ENABLED", false),
TradeThreshold: getFloat("TRADE_THRESHOLD", 0.15),
TradeAmountUSD: getFloat("TRADE_AMOUNT_USD", 10),
TradeCooldownMs: 30000,
TradeEnabled: getBool("TRADE_ENABLED", jsonCfg.TradeEnabled),
TradeThreshold: getFloat("TRADE_THRESHOLD", jsonCfg.TradeThreshold),
TradeAmountUSD: getFloat("TRADE_AMOUNT_USD", jsonCfg.TradeAmountUSD),
TradeCooldownMs: int(getFloat("TRADE_COOLDOWN_MS", float64(jsonCfg.TradeCooldownMs))),
TestMode: getBool("TEST_MODE", false),
MockSlippagePct: getFloat("MOCK_SLIPPAGE_PCT", 0.005),
TestMode: getBool("TEST_MODE", jsonCfg.TestMode),
MockSlippagePct: getFloat("MOCK_SLIPPAGE_PCT", jsonCfg.MockSlippagePct),
BitgetAPIKey: getEnv("BITGET_API_KEY", ""),
BitgetAPISecret: getEnv("BITGET_API_SECRET", ""),
@@ -81,3 +101,50 @@ func LoadConfig() *Config {
HLAddress: getEnv("HL_ADDRESS", ""),
}
}
func loadJSONConfig() jsonConfig {
def := jsonConfig{
ArbThreshold: 0.03,
ScanIntervalMs: 500,
TradeThreshold: 0.15,
TradeAmountUSD: 10,
TradeCooldownMs: 30000,
AlertCooldownSec: 300,
MockSlippagePct: 0.005,
}
data, err := os.ReadFile("config.json")
if err != nil {
return def // file not found, use code defaults
}
var cfg jsonConfig
if err := json.Unmarshal(data, &cfg); err != nil {
return def
}
// Only override if the JSON file actually set the field
if cfg.ArbThreshold != 0 {
def.ArbThreshold = cfg.ArbThreshold
}
if cfg.ScanIntervalMs != 0 {
def.ScanIntervalMs = cfg.ScanIntervalMs
}
if cfg.TradeThreshold != 0 {
def.TradeThreshold = cfg.TradeThreshold
}
if cfg.TradeAmountUSD != 0 {
def.TradeAmountUSD = cfg.TradeAmountUSD
}
if cfg.TradeCooldownMs != 0 {
def.TradeCooldownMs = cfg.TradeCooldownMs
}
if cfg.AlertCooldownSec != 0 {
def.AlertCooldownSec = cfg.AlertCooldownSec
}
if cfg.MockSlippagePct != 0 {
def.MockSlippagePct = cfg.MockSlippagePct
}
return def
}