From c28dbef74a529d700a9e23555ba1c8cfab31a0eb Mon Sep 17 00:00:00 2001 From: perfhelf Date: Thu, 23 Apr 2026 00:24:39 +0800 Subject: [PATCH] add crude oil godview index --- engine/godview.py | 7 ++++++- frontend/app/page.tsx | 15 +++++++++------ frontend/app/providers.tsx | 20 ++++++++------------ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/engine/godview.py b/engine/godview.py index 96fd4f3..71b7b2e 100644 --- a/engine/godview.py +++ b/engine/godview.py @@ -28,6 +28,7 @@ 'MYR': 'USDMYR=X', 'XAU': 'GC=F', 'XAG': 'SI=F', + 'USO': 'CL=F', 'XCU': 'HG=F', 'ZAR': 'USDZAR=X', 'KRW': 'USDKRW=X', @@ -113,6 +114,7 @@ def get_c(ticker): myr = get_c(SYMBOLS_MAP['MYR']) xau = get_c(SYMBOLS_MAP['XAU']) xag = get_c(SYMBOLS_MAP['XAG']) + uso = get_c(SYMBOLS_MAP['USO']) xcu = get_c(SYMBOLS_MAP['XCU']) zar = get_c(SYMBOLS_MAP['ZAR']) krw = get_c(SYMBOLS_MAP['KRW']) @@ -156,6 +158,7 @@ def get_c(ticker): indices['MYR'] = (1/myr)/0.22371 + (eur/myr)/0.23937 + (gbp/myr)/0.27740 + (jpy/myr)/31.99552 + (aud/myr)/0.14765 indices['XAU'] = xau/4629 + (xau/eur)/3973 + (xau/gbp)/3444 + (xau*jpy)/734159 + (xau/aud)/6929 indices['XAG'] = xag/85.23 + (xag/eur)/73.16 + (xag/gbp)/63.41 + (xag*jpy)/13517 + (xag/aud)/127.59 + indices['USO'] = uso/93 + (uso/eur)/79.38 + (uso/gbp)/68.9 + (uso*jpy)/14832 + (uso/aud)/129.92 indices['XCU'] = xcu/6.05 + (xcu/eur)/5.19 + (xcu/gbp)/4.50 + (xcu*jpy)/959.5 + (xcu/aud)/9.06 indices['ZAR'] = (1/zar)/0.06109 + (eur/zar)/0.07116 + (gbp/zar)/0.08210 + (jpy/zar)/9.688 + (aud/zar)/0.04080 indices['KRW'] = (1/krw)/0.000682 + (eur/krw)/0.000794 + (gbp/krw)/0.000916 + (jpy/krw)/0.10818 + (aud/krw)/0.000455 @@ -646,6 +649,7 @@ def apply_formula(series_getter): myr = series_getter(SYMBOLS_MAP['MYR']) xau = series_getter(SYMBOLS_MAP['XAU']) xag = series_getter(SYMBOLS_MAP['XAG']) + uso = series_getter(SYMBOLS_MAP['USO']) xcu = series_getter(SYMBOLS_MAP['XCU']) zar = series_getter(SYMBOLS_MAP['ZAR']) krw = series_getter(SYMBOLS_MAP['KRW']) @@ -689,6 +693,7 @@ def apply_formula(series_getter): res['MYR'] = (1/myr)/0.22371 + (eur/myr)/0.23937 + (gbp/myr)/0.27740 + (jpy/myr)/31.99552 + (aud/myr)/0.14765 res['XAU'] = xau/4629 + (xau/eur)/3973 + (xau/gbp)/3444 + (xau*jpy)/734159 + (xau/aud)/6929 res['XAG'] = xag/85.23 + (xag/eur)/73.16 + (xag/gbp)/63.41 + (xag*jpy)/13517 + (xag/aud)/127.59 + res['USO'] = uso/93 + (uso/eur)/79.38 + (uso/gbp)/68.9 + (uso*jpy)/14832 + (uso/aud)/129.92 res['XCU'] = xcu/6.05 + (xcu/eur)/5.19 + (xcu/gbp)/4.50 + (xcu*jpy)/959.5 + (xcu/aud)/9.06 res['ZAR'] = (1/zar)/0.06109 + (eur/zar)/0.07116 + (gbp/zar)/0.08210 + (jpy/zar)/9.688 + (aud/zar)/0.04080 res['KRW'] = (1/krw)/0.000682 + (eur/krw)/0.000794 + (gbp/krw)/0.000916 + (jpy/krw)/0.10818 + (aud/krw)/0.000455 @@ -733,7 +738,7 @@ def apply_formula(series_getter): # Dynamic minimum length check # Commodities and Emerging currencies might have shorter history in Yahoo min_len = 200 - if symbol in ['XAU', 'XAG', 'XCU', 'ZAR', 'KRW', 'BRL', + if symbol in ['XAU', 'XAG', 'USO', 'XCU', 'ZAR', 'KRW', 'BRL', 'CN50', 'HK50', 'SG30', 'ASX200', 'CA60', 'NL25', 'FRA40', 'GER40', 'EUSTX50', 'IT40', 'SWI20', 'UK100', 'SPX500', 'NDQ100', 'US2000', 'US30', 'JPN225']: min_len = 50 diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index 3712da1..2f35bb6 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -1,6 +1,6 @@ 'use client' -import { useEffect, useState } from 'react' +import { useEffect, useState, useSyncExternalStore } from 'react' import { supabase } from '@/lib/supabase' import { useTheme } from './providers' @@ -46,7 +46,7 @@ const SYMBOL_NAMES: Record = { AUD: '澳元', CAD: '加元', NZD: '纽元', CHF: '瑞郎', SGD: '新元', MXN: '比索', SEK: '瑞典', NOK: '挪威', CNH: '人民币', MYR: '林吉特', - XAU: '黄金', XAG: '白银', XCU: '铜', + XAU: '黄金', XAG: '白银', USO: '原油', XCU: '铜', ZAR: '南非兰特', KRW: '韩元', BRL: '雷亚尔', // Stock Indices CN50: '中国A50', HK50: '恒生指数', SG30: '新加坡30', @@ -75,6 +75,7 @@ const TV_FORMULAS: Record = { MYR: '1/USDMYR/0.22371+FX:EURUSD/USDMYR/0.23937+FX:GBPUSD/USDMYR/0.27740+FX:USDJPY/USDMYR/31.99552+FX:AUDUSD/USDMYR/0.14765', XAU: 'XAUUSD/4629 + XAUUSD/FX:EURUSD/3973 + XAUUSD/FX:GBPUSD/3444 + XAUUSD*FX:USDJPY/734159 + XAUUSD/FX:AUDUSD/6929', XAG: 'XAGUSD/85.23 + XAGUSD/FX:EURUSD/73.16 + XAGUSD/FX:GBPUSD/63.41 + XAGUSD*FX:USDJPY/13517 + XAGUSD/FX:AUDUSD/127.59', + USO: 'EIGHTCAP:USOUSD/93 + EIGHTCAP:USOUSD/FX:EURUSD/79.38 + EIGHTCAP:USOUSD/FX:GBPUSD/68.9 + EIGHTCAP:USOUSD*FX:USDJPY/14832 + EIGHTCAP:USOUSD/FX:AUDUSD/129.92', XCU: 'HG1!/6.05 + HG1!/FX:EURUSD/5.19 + HG1!/FX:GBPUSD/4.50 + HG1!*FX:USDJPY/959.5 + HG1!/FX:AUDUSD/9.06', ZAR: '1/USDZAR/0.06109 + FX:EURUSD/USDZAR/0.07116 + FX:GBPUSD/USDZAR/0.08210 + FX:USDJPY/USDZAR/9.688 + FX:AUDUSD/USDZAR/0.04080', KRW: '1/USDKRW/0.000682 + FX:EURUSD/USDKRW/0.000794 + FX:GBPUSD/USDKRW/0.000916 + FX:USDJPY/USDKRW/0.10818 + FX:AUDUSD/USDKRW/0.000455', @@ -226,11 +227,13 @@ function ViewModeToggle({ selected, onSelect }: { selected: ViewMode, onSelect: function ThemeToggle() { const { theme, setTheme } = useTheme() - const [mounted, setMounted] = useState(false) - - useEffect(() => { setMounted(true) }, []) + const isClient = useSyncExternalStore( + () => () => {}, + () => true, + () => false, + ) - if (!mounted) return null + if (!isClient) return null const options = [ { key: 'light' as const, icon: '☀️' }, diff --git a/frontend/app/providers.tsx b/frontend/app/providers.tsx index e9ee963..32387b4 100644 --- a/frontend/app/providers.tsx +++ b/frontend/app/providers.tsx @@ -13,20 +13,16 @@ const ThemeContext = createContext<{ }) export function ThemeProvider({ children }: { children: React.ReactNode }) { - const [theme, setTheme] = useState('system') - const [mounted, setMounted] = useState(false) - - useEffect(() => { - setMounted(true) - const saved = localStorage.getItem('theme') as Theme - if (saved) { - setTheme(saved) + const [theme, setTheme] = useState(() => { + if (typeof window === 'undefined') { + return 'system' } - }, []) - useEffect(() => { - if (!mounted) return + const saved = window.localStorage.getItem('theme') + return saved === 'light' || saved === 'dark' || saved === 'system' ? saved : 'system' + }) + useEffect(() => { const root = window.document.documentElement root.classList.remove('light', 'dark') @@ -37,7 +33,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) { root.classList.add(theme) } localStorage.setItem('theme', theme) - }, [theme, mounted]) + }, [theme]) useEffect(() => { const media = window.matchMedia('(prefers-color-scheme: dark)')