data fixes; indicator=>workspace sync
This commit is contained in:
@@ -5,180 +5,146 @@ import { useChartStore } from '../stores/chart'
|
||||
import type { IndicatorInstance } from '../stores/indicators'
|
||||
|
||||
/**
|
||||
* Mapping between TA-Lib indicator names and TradingView indicator names
|
||||
* Only includes indicators that are present in BOTH systems (inner join)
|
||||
* Mapping between pandas-ta indicator function names and TradingView indicator display names.
|
||||
* Only includes indicators present in BOTH systems (inner join).
|
||||
* Keys are lowercase pandas-ta function names; values are TradingView display strings.
|
||||
*/
|
||||
const TALIB_TO_TV_NAMES: Record<string, string> = {
|
||||
// Overlap Studies (14)
|
||||
'SMA': 'Moving Average',
|
||||
'EMA': 'Moving Average Exponential',
|
||||
'WMA': 'Weighted Moving Average',
|
||||
'DEMA': 'DEMA',
|
||||
'TEMA': 'TEMA',
|
||||
'TRIMA': 'Triangular Moving Average',
|
||||
'KAMA': 'KAMA',
|
||||
'MAMA': 'MESA Adaptive Moving Average',
|
||||
'T3': 'T3',
|
||||
'BBANDS': 'Bollinger Bands',
|
||||
'MIDPOINT': 'Midpoint',
|
||||
'MIDPRICE': 'Midprice',
|
||||
'SAR': 'Parabolic SAR',
|
||||
'HT_TRENDLINE': 'Hilbert Transform - Instantaneous Trendline',
|
||||
const PANDAS_TA_TO_TV_NAMES: Record<string, string> = {
|
||||
// Overlap / Moving Averages (17)
|
||||
'sma': 'Moving Average',
|
||||
'ema': 'Moving Average Exponential',
|
||||
'wma': 'Moving Average Weighted',
|
||||
'dema': 'Double EMA',
|
||||
'tema': 'Triple EMA',
|
||||
'trima': 'Triangular Moving Average',
|
||||
'kama': 'Moving Average Adaptive',
|
||||
't3': 'T3',
|
||||
'hma': 'Hull Moving Average',
|
||||
'alma': 'Arnaud Legoux Moving Average',
|
||||
'midpoint': 'Midpoint',
|
||||
'midprice': 'Midprice',
|
||||
'supertrend': 'SuperTrend',
|
||||
'ichimoku': 'Ichimoku Cloud',
|
||||
'vwap': 'VWAP',
|
||||
'vwma': 'VWMA',
|
||||
'bbands': 'Bollinger Bands',
|
||||
|
||||
// Momentum Indicators (21)
|
||||
'RSI': 'Relative Strength Index',
|
||||
'MOM': 'Momentum',
|
||||
'ROC': 'Rate of Change',
|
||||
'TRIX': 'TRIX',
|
||||
'CMO': 'Chande Momentum Oscillator',
|
||||
'DX': 'Directional Movement Index',
|
||||
'ADX': 'Average Directional Movement Index',
|
||||
'ADXR': 'Average Directional Movement Index Rating',
|
||||
'APO': 'Absolute Price Oscillator',
|
||||
'PPO': 'Percentage Price Oscillator',
|
||||
'MACD': 'MACD',
|
||||
'MFI': 'Money Flow Index',
|
||||
'STOCH': 'Stochastic',
|
||||
'STOCHF': 'Stochastic Fast',
|
||||
'STOCHRSI': 'Stochastic RSI',
|
||||
'WILLR': 'Williams %R',
|
||||
'CCI': 'Commodity Channel Index',
|
||||
'AROON': 'Aroon',
|
||||
'AROONOSC': 'Aroon Oscillator',
|
||||
'BOP': 'Balance Of Power',
|
||||
'ULTOSC': 'Ultimate Oscillator',
|
||||
// Momentum (22)
|
||||
'rsi': 'Relative Strength Index',
|
||||
'macd': 'MACD',
|
||||
'stoch': 'Stochastic',
|
||||
'stochrsi':'Stochastic RSI',
|
||||
'cci': 'Commodity Channel Index',
|
||||
'willr': 'Williams %R',
|
||||
'mom': 'Momentum',
|
||||
'roc': 'Rate Of Change',
|
||||
'trix': 'TRIX',
|
||||
'cmo': 'Chande Momentum Oscillator',
|
||||
'adx': 'Average Directional Index',
|
||||
'aroon': 'Aroon',
|
||||
'ao': 'Awesome Oscillator',
|
||||
'bop': 'Balance of Power',
|
||||
'uo': 'Ultimate Oscillator',
|
||||
'apo': 'Price Oscillator',
|
||||
'mfi': 'Money Flow Index',
|
||||
'coppock': 'Coppock Curve',
|
||||
'dpo': 'Detrended Price Oscillator',
|
||||
'fisher': 'Fisher Transform',
|
||||
'rvgi': 'Relative Vigor Index',
|
||||
'kst': 'Know Sure Thing',
|
||||
|
||||
// Volume Indicators (3)
|
||||
'AD': 'Chaikin A/D Line',
|
||||
'ADOSC': 'Chaikin A/D Oscillator',
|
||||
'OBV': 'On Balance Volume',
|
||||
// Volatility (3)
|
||||
'atr': 'Average True Range',
|
||||
'kc': 'Keltner Channels',
|
||||
'donchian': 'Donchian Channels',
|
||||
|
||||
// Volatility Indicators (3)
|
||||
'ATR': 'Average True Range',
|
||||
'NATR': 'Normalized Average True Range',
|
||||
'TRANGE': 'True Range',
|
||||
// Volume (8)
|
||||
'obv': 'On Balance Volume',
|
||||
'ad': 'Accumulation/Distribution',
|
||||
'adosc': 'Chaikin Oscillator',
|
||||
'cmf': 'Chaikin Money Flow',
|
||||
'eom': 'Ease of Movement',
|
||||
'efi': "Elder's Force Index",
|
||||
'kvo': 'Klinger Oscillator',
|
||||
'pvt': 'Price Volume Trend',
|
||||
|
||||
// Price Transform (4)
|
||||
'AVGPRICE': 'Average Price',
|
||||
'MEDPRICE': 'Median Price',
|
||||
'TYPPRICE': 'Typical Price',
|
||||
'WCLPRICE': 'Weighted Close Price',
|
||||
// Statistics / Price Transforms (6)
|
||||
'stdev': 'Standard Deviation',
|
||||
'linreg': 'Linear Regression Curve',
|
||||
'slope': 'Linear Regression Slope',
|
||||
'hl2': 'Median Price',
|
||||
'hlc3': 'Typical Price',
|
||||
'ohlc4': 'Average Price',
|
||||
|
||||
// Cycle Indicators (5)
|
||||
'HT_DCPERIOD': 'Hilbert Transform - Dominant Cycle Period',
|
||||
'HT_DCPHASE': 'Hilbert Transform - Dominant Cycle Phase',
|
||||
'HT_PHASOR': 'Hilbert Transform - Phasor Components',
|
||||
'HT_SINE': 'Hilbert Transform - SineWave',
|
||||
'HT_TRENDMODE': 'Hilbert Transform - Trend vs Cycle Mode',
|
||||
|
||||
// Statistic Functions (9)
|
||||
'BETA': 'Beta',
|
||||
'CORREL': 'Pearson\'s Correlation Coefficient',
|
||||
'LINEARREG': 'Linear Regression',
|
||||
'LINEARREG_ANGLE': 'Linear Regression Angle',
|
||||
'LINEARREG_INTERCEPT': 'Linear Regression Intercept',
|
||||
'LINEARREG_SLOPE': 'Linear Regression Slope',
|
||||
'STDDEV': 'Standard Deviation',
|
||||
'TSF': 'Time Series Forecast',
|
||||
'VAR': 'Variance',
|
||||
// Trend (3)
|
||||
'psar': 'Parabolic SAR',
|
||||
'vortex': 'Vortex Indicator',
|
||||
'chop': 'Choppiness Index',
|
||||
}
|
||||
|
||||
// Total: 60 TA-Lib indicators
|
||||
// Total: 59 indicators
|
||||
|
||||
/**
|
||||
* Custom indicators (implemented in backend, not in TA-Lib)
|
||||
* Reverse mapping from TradingView display name to pandas-ta function name
|
||||
*/
|
||||
const CUSTOM_TO_TV_NAMES: Record<string, string> = {
|
||||
'VWAP': 'VWAP',
|
||||
'VWMA': 'VWMA',
|
||||
'HMA': 'Hull Moving Average',
|
||||
'SUPERTREND': 'SuperTrend',
|
||||
'DONCHIAN': 'Donchian Channels',
|
||||
'KELTNER': 'Keltner Channels',
|
||||
'CMF': 'Chaikin Money Flow',
|
||||
'VORTEX': 'Vortex Indicator',
|
||||
'AO': 'Awesome Oscillator',
|
||||
'AC': 'Accelerator Oscillator',
|
||||
'CHOP': 'Choppiness Index',
|
||||
'MASS': 'Mass Index',
|
||||
}
|
||||
|
||||
// Combined mapping (TA-Lib + Custom)
|
||||
const ALL_BACKEND_TO_TV_NAMES: Record<string, string> = {
|
||||
...TALIB_TO_TV_NAMES,
|
||||
...CUSTOM_TO_TV_NAMES
|
||||
}
|
||||
|
||||
// Total: 72 indicators (60 TA-Lib + 12 Custom)
|
||||
|
||||
/**
|
||||
* Reverse mapping from TradingView to backend
|
||||
*/
|
||||
const TV_TO_TALIB_NAMES: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(TALIB_TO_TV_NAMES).map(([k, v]) => [v, k])
|
||||
)
|
||||
|
||||
const TV_TO_CUSTOM_NAMES: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(CUSTOM_TO_TV_NAMES).map(([k, v]) => [v, k])
|
||||
)
|
||||
|
||||
const TV_TO_BACKEND_NAMES: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(ALL_BACKEND_TO_TV_NAMES).map(([k, v]) => [v, k])
|
||||
const TV_TO_PANDAS_TA_NAMES: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(PANDAS_TA_TO_TV_NAMES).map(([k, v]) => [v, k])
|
||||
)
|
||||
|
||||
/**
|
||||
* Convert TA-Lib parameters to TradingView inputs
|
||||
* Convert pandas-ta parameters to TradingView inputs
|
||||
*/
|
||||
function convertTALibParamsToTVInputs(talibName: string, talibParams: Record<string, any>): Record<string, any> {
|
||||
function convertPandasTaParamsToTVInputs(pandasTaName: string, params: Record<string, any>): Record<string, any> {
|
||||
const tvInputs: Record<string, any> = {}
|
||||
|
||||
// Common parameter mappings
|
||||
const paramMapping: Record<string, string> = {
|
||||
'timeperiod': 'length',
|
||||
'fastperiod': 'fastLength',
|
||||
'slowperiod': 'slowLength',
|
||||
'signalperiod': 'signalLength',
|
||||
'nbdevup': 'mult',
|
||||
'nbdevdn': 'mult',
|
||||
'fastlimit': 'fastLimit',
|
||||
'slowlimit': 'slowLimit',
|
||||
'acceleration': 'start',
|
||||
'maximum': 'increment',
|
||||
'fastk_period': 'kPeriod',
|
||||
'slowk_period': 'kPeriod',
|
||||
'slowd_period': 'dPeriod',
|
||||
'fastd_period': 'dPeriod',
|
||||
}
|
||||
|
||||
// Special handling for specific indicators
|
||||
if (talibName === 'BBANDS') {
|
||||
tvInputs.length = talibParams.timeperiod || 20
|
||||
tvInputs.mult = talibParams.nbdevup || 2
|
||||
if (pandasTaName === 'bbands') {
|
||||
tvInputs.length = params.length || 20
|
||||
tvInputs.mult = params.upper_std ?? params.std ?? 2
|
||||
tvInputs.source = 'close'
|
||||
} else if (talibName === 'MACD') {
|
||||
tvInputs.fastLength = talibParams.fastperiod || 12
|
||||
tvInputs.slowLength = talibParams.slowperiod || 26
|
||||
tvInputs.signalLength = talibParams.signalperiod || 9
|
||||
} else if (pandasTaName === 'macd') {
|
||||
tvInputs.fastLength = params.fast || 12
|
||||
tvInputs.slowLength = params.slow || 26
|
||||
tvInputs.signalLength = params.signal || 9
|
||||
tvInputs.source = 'close'
|
||||
} else if (talibName === 'RSI') {
|
||||
tvInputs.length = talibParams.timeperiod || 14
|
||||
} else if (pandasTaName === 'stoch') {
|
||||
tvInputs.kPeriod = params.k || 14
|
||||
tvInputs.dPeriod = params.d || 3
|
||||
tvInputs.smoothK = params.smooth_k || 3
|
||||
} else if (pandasTaName === 'stochrsi') {
|
||||
tvInputs.length = params.length || 14
|
||||
tvInputs.rsiLength = params.rsi_length || 14
|
||||
tvInputs.kPeriod = params.k || 3
|
||||
tvInputs.dPeriod = params.d || 3
|
||||
} else if (pandasTaName === 'psar') {
|
||||
tvInputs.start = params.af0 || 0.02
|
||||
tvInputs.increment = params.af || 0.02
|
||||
tvInputs.max = params.max_af || 0.2
|
||||
} else if (pandasTaName === 'ichimoku') {
|
||||
tvInputs.conversionPeriod = params.tenkan || 9
|
||||
tvInputs.basePeriod = params.kijun || 26
|
||||
tvInputs.laggingSpanPeriod = params.senkou || 52
|
||||
} else if (pandasTaName === 'vwap') {
|
||||
tvInputs.anchor = params.anchor || 'D'
|
||||
} else if (['apo', 'ppo'].includes(pandasTaName)) {
|
||||
tvInputs.fastLength = params.fast || 12
|
||||
tvInputs.slowLength = params.slow || 26
|
||||
tvInputs.source = 'close'
|
||||
} else if (['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA'].includes(talibName)) {
|
||||
tvInputs.length = talibParams.timeperiod || 14
|
||||
tvInputs.source = 'close'
|
||||
} else if (talibName === 'STOCH') {
|
||||
tvInputs.kPeriod = talibParams.fastk_period || 14
|
||||
tvInputs.dPeriod = talibParams.slowd_period || 3
|
||||
tvInputs.smoothK = talibParams.slowk_period || 3
|
||||
} else if (talibName === 'ATR') {
|
||||
tvInputs.length = talibParams.timeperiod || 14
|
||||
} else if (talibName === 'CCI') {
|
||||
tvInputs.length = talibParams.timeperiod || 20
|
||||
} else if (pandasTaName === 'uo') {
|
||||
tvInputs.fast = params.fast || 7
|
||||
tvInputs.medium = params.medium || 14
|
||||
tvInputs.slow = params.slow || 28
|
||||
} else if (pandasTaName === 'adosc') {
|
||||
tvInputs.fastLength = params.fast || 3
|
||||
tvInputs.slowLength = params.slow || 10
|
||||
} else if (pandasTaName === 'kc') {
|
||||
tvInputs.length = params.length || 20
|
||||
tvInputs.mult = params.scalar || 2
|
||||
} else {
|
||||
// Generic parameter conversion
|
||||
for (const [talibParam, value] of Object.entries(talibParams)) {
|
||||
const tvParam = paramMapping[talibParam] || talibParam
|
||||
tvInputs[tvParam] = value
|
||||
// Generic: pass length through; skip source
|
||||
if (params.length !== undefined) tvInputs.length = params.length
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
if (k === 'length' || k === 'source') continue
|
||||
tvInputs[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,68 +152,72 @@ function convertTALibParamsToTVInputs(talibName: string, talibParams: Record<str
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert TradingView inputs to TA-Lib parameters
|
||||
* Convert TradingView inputs to pandas-ta parameters
|
||||
*/
|
||||
function convertTVInputsToTALibParams(tvName: string, tvInputs: Record<string, any>): { talibName: string | null, talibParams: Record<string, any> } {
|
||||
const talibName = TV_TO_BACKEND_NAMES[tvName] || null
|
||||
if (!talibName) {
|
||||
console.warn('[Indicators] No backend mapping for TradingView indicator:', tvName)
|
||||
return { talibName: null, talibParams: {} }
|
||||
function convertTVInputsToPandasTaParams(tvName: string, tvInputs: Record<string, any>): { pandasTaName: string | null, pandasTaParams: Record<string, any> } {
|
||||
const pandasTaName = TV_TO_PANDAS_TA_NAMES[tvName] || null
|
||||
if (!pandasTaName) {
|
||||
console.warn('[Indicators] No pandas-ta mapping for TradingView indicator:', tvName)
|
||||
return { pandasTaName: null, pandasTaParams: {} }
|
||||
}
|
||||
|
||||
const talibParams: Record<string, any> = {}
|
||||
const pandasTaParams: Record<string, any> = {}
|
||||
|
||||
// Reverse parameter mappings
|
||||
const reverseMapping: Record<string, string> = {
|
||||
'length': 'timeperiod',
|
||||
'fastLength': 'fastperiod',
|
||||
'slowLength': 'slowperiod',
|
||||
'signalLength': 'signalperiod',
|
||||
'mult': 'nbdevup',
|
||||
'fastLimit': 'fastlimit',
|
||||
'slowLimit': 'slowlimit',
|
||||
'start': 'acceleration',
|
||||
'increment': 'maximum',
|
||||
'kPeriod': 'fastk_period',
|
||||
'dPeriod': 'slowd_period',
|
||||
'smoothK': 'slowk_period',
|
||||
}
|
||||
|
||||
// Special handling for specific indicators
|
||||
if (talibName === 'BBANDS') {
|
||||
// TradingView uses in_0 for length, in_1 for multiplier
|
||||
talibParams.timeperiod = tvInputs.in_0 || tvInputs.length || 20
|
||||
talibParams.nbdevup = tvInputs.in_1 || tvInputs.mult || 2
|
||||
talibParams.nbdevdn = tvInputs.in_1 || tvInputs.mult || 2
|
||||
talibParams.matype = 0 // SMA
|
||||
} else if (talibName === 'MACD') {
|
||||
talibParams.fastperiod = tvInputs.fastLength || 12
|
||||
talibParams.slowperiod = tvInputs.slowLength || 26
|
||||
talibParams.signalperiod = tvInputs.signalLength || 9
|
||||
} else if (talibName === 'RSI') {
|
||||
talibParams.timeperiod = tvInputs.in_0 || tvInputs.length || 14
|
||||
} else if (['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA'].includes(talibName)) {
|
||||
talibParams.timeperiod = tvInputs.in_0 || tvInputs.length || 14
|
||||
} else if (talibName === 'STOCH') {
|
||||
talibParams.fastk_period = tvInputs.kPeriod || 14
|
||||
talibParams.slowd_period = tvInputs.dPeriod || 3
|
||||
talibParams.slowk_period = tvInputs.smoothK || 3
|
||||
talibParams.slowk_matype = 0 // SMA
|
||||
talibParams.slowd_matype = 0 // SMA
|
||||
} else if (talibName === 'ATR') {
|
||||
talibParams.timeperiod = tvInputs.length || 14
|
||||
} else if (talibName === 'CCI') {
|
||||
talibParams.timeperiod = tvInputs.length || 20
|
||||
if (pandasTaName === 'bbands') {
|
||||
pandasTaParams.length = tvInputs.in_0 ?? tvInputs.length ?? 20
|
||||
const std = tvInputs.in_1 ?? tvInputs.mult ?? 2
|
||||
pandasTaParams.upper_std = std
|
||||
pandasTaParams.lower_std = std
|
||||
} else if (pandasTaName === 'macd') {
|
||||
pandasTaParams.fast = tvInputs.fastLength ?? 12
|
||||
pandasTaParams.slow = tvInputs.slowLength ?? 26
|
||||
pandasTaParams.signal = tvInputs.signalLength ?? 9
|
||||
} else if (pandasTaName === 'stoch') {
|
||||
pandasTaParams.k = tvInputs.kPeriod ?? 14
|
||||
pandasTaParams.d = tvInputs.dPeriod ?? 3
|
||||
pandasTaParams.smooth_k = tvInputs.smoothK ?? 3
|
||||
} else if (pandasTaName === 'stochrsi') {
|
||||
pandasTaParams.length = tvInputs.length ?? 14
|
||||
pandasTaParams.rsi_length = tvInputs.rsiLength ?? 14
|
||||
pandasTaParams.k = tvInputs.kPeriod ?? 3
|
||||
pandasTaParams.d = tvInputs.dPeriod ?? 3
|
||||
} else if (pandasTaName === 'psar') {
|
||||
pandasTaParams.af0 = tvInputs.start ?? 0.02
|
||||
pandasTaParams.af = tvInputs.increment ?? 0.02
|
||||
pandasTaParams.max_af = tvInputs.max ?? 0.2
|
||||
} else if (pandasTaName === 'ichimoku') {
|
||||
pandasTaParams.tenkan = tvInputs.conversionPeriod ?? 9
|
||||
pandasTaParams.kijun = tvInputs.basePeriod ?? 26
|
||||
pandasTaParams.senkou = tvInputs.laggingSpanPeriod ?? 52
|
||||
} else if (pandasTaName === 'vwap') {
|
||||
pandasTaParams.anchor = tvInputs.anchor ?? 'D'
|
||||
} else if (['apo', 'ppo'].includes(pandasTaName)) {
|
||||
pandasTaParams.fast = tvInputs.fastLength ?? 12
|
||||
pandasTaParams.slow = tvInputs.slowLength ?? 26
|
||||
} else if (pandasTaName === 'uo') {
|
||||
pandasTaParams.fast = tvInputs.fast ?? 7
|
||||
pandasTaParams.medium = tvInputs.medium ?? 14
|
||||
pandasTaParams.slow = tvInputs.slow ?? 28
|
||||
} else if (pandasTaName === 'adosc') {
|
||||
pandasTaParams.fast = tvInputs.fastLength ?? 3
|
||||
pandasTaParams.slow = tvInputs.slowLength ?? 10
|
||||
} else if (pandasTaName === 'kc') {
|
||||
pandasTaParams.length = tvInputs.length ?? 20
|
||||
pandasTaParams.scalar = tvInputs.mult ?? 2
|
||||
} else {
|
||||
// Generic parameter conversion
|
||||
for (const [tvParam, value] of Object.entries(tvInputs)) {
|
||||
if (tvParam === 'source') continue // Skip source parameter
|
||||
const talibParam = reverseMapping[tvParam] || tvParam
|
||||
talibParams[talibParam] = value
|
||||
// Generic: extract length; skip source
|
||||
for (const [k, v] of Object.entries(tvInputs)) {
|
||||
if (k === 'source') continue
|
||||
pandasTaParams[k] = v
|
||||
}
|
||||
// Normalise TV in_0 → length for simple single-period indicators
|
||||
if (tvInputs.in_0 !== undefined && pandasTaParams.length === undefined) {
|
||||
pandasTaParams.length = tvInputs.in_0
|
||||
delete pandasTaParams.in_0
|
||||
}
|
||||
}
|
||||
|
||||
return { talibName, talibParams }
|
||||
return { pandasTaName, pandasTaParams }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,12 +289,12 @@ export function useTradingViewIndicators(tvWidget: IChartingLibraryWidget) {
|
||||
|
||||
console.log('[Indicators] Study name extracted:', studyName)
|
||||
|
||||
const talibName = TV_TO_BACKEND_NAMES[studyName]
|
||||
console.log('[Indicators] Backend mapping:', studyName, '->', talibName)
|
||||
const pandasTaName = TV_TO_PANDAS_TA_NAMES[studyName]
|
||||
console.log('[Indicators] pandas-ta mapping:', studyName, '->', pandasTaName)
|
||||
|
||||
if (!talibName) {
|
||||
console.log('[Indicators] TradingView study not mapped to backend:', studyName)
|
||||
console.log('[Indicators] Available mappings:', Object.keys(TV_TO_BACKEND_NAMES).slice(0, 10))
|
||||
if (!pandasTaName) {
|
||||
console.log('[Indicators] TradingView study not mapped to pandas-ta:', studyName)
|
||||
console.log('[Indicators] Available mappings:', Object.keys(TV_TO_PANDAS_TA_NAMES).slice(0, 10))
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -357,16 +327,16 @@ export function useTradingViewIndicators(tvWidget: IChartingLibraryWidget) {
|
||||
|
||||
console.log('[Indicators] TV inputs:', tvInputs)
|
||||
|
||||
const { talibParams } = convertTVInputsToTALibParams(studyName, tvInputs)
|
||||
console.log('[Indicators] Converted TA-Lib params:', talibParams)
|
||||
const { pandasTaParams } = convertTVInputsToPandasTaParams(studyName, tvInputs)
|
||||
console.log('[Indicators] Converted pandas-ta params:', pandasTaParams)
|
||||
|
||||
const now = Math.floor(Date.now() / 1000)
|
||||
|
||||
const indicator = {
|
||||
id: studyId || tvStudy.id || `ind_${Date.now()}`,
|
||||
talib_name: talibName,
|
||||
instance_name: `${talibName}_${Date.now()}`,
|
||||
parameters: talibParams,
|
||||
pandas_ta_name: pandasTaName,
|
||||
instance_name: `${pandasTaName}_${Date.now()}`,
|
||||
parameters: pandasTaParams,
|
||||
tv_study_id: studyId || tvStudy.id,
|
||||
tv_indicator_name: studyName,
|
||||
tv_inputs: tvInputs,
|
||||
@@ -591,17 +561,17 @@ export function useTradingViewIndicators(tvWidget: IChartingLibraryWidget) {
|
||||
|
||||
console.log('[Indicators] TV inputs:', tvInputs)
|
||||
|
||||
const { talibParams } = convertTVInputsToTALibParams(studyName, tvInputs)
|
||||
const { pandasTaParams } = convertTVInputsToPandasTaParams(studyName, tvInputs)
|
||||
|
||||
console.log('[Indicators] Old params:', existingIndicator.parameters)
|
||||
console.log('[Indicators] New params:', talibParams)
|
||||
console.log('[Indicators] New params:', pandasTaParams)
|
||||
|
||||
// Update the store with new parameters
|
||||
if (JSON.stringify(existingIndicator.parameters) !== JSON.stringify(talibParams)) {
|
||||
if (JSON.stringify(existingIndicator.parameters) !== JSON.stringify(pandasTaParams)) {
|
||||
console.log('[Indicators] Parameters changed, updating store...')
|
||||
isUpdatingStore = true
|
||||
indicatorStore.updateIndicator(existingIndicator.id, {
|
||||
parameters: talibParams,
|
||||
parameters: pandasTaParams,
|
||||
tv_inputs: tvInputs
|
||||
})
|
||||
console.log('[Indicators] Indicator updated in store!')
|
||||
@@ -816,14 +786,14 @@ export function useTradingViewIndicators(tvWidget: IChartingLibraryWidget) {
|
||||
if (!chart) return
|
||||
|
||||
const currentSymbol = chartStore.symbol
|
||||
const tvName = ALL_BACKEND_TO_TV_NAMES[indicator.talib_name]
|
||||
const tvName = PANDAS_TA_TO_TV_NAMES[indicator.pandas_ta_name]
|
||||
|
||||
if (!tvName) {
|
||||
console.warn('[Indicators] No TradingView mapping for backend indicator:', indicator.talib_name)
|
||||
console.warn('[Indicators] No TradingView mapping for pandas-ta indicator:', indicator.pandas_ta_name)
|
||||
return
|
||||
}
|
||||
|
||||
const tvInputs = convertTALibParamsToTVInputs(indicator.talib_name, indicator.parameters)
|
||||
const tvInputs = convertPandasTaParamsToTVInputs(indicator.pandas_ta_name, indicator.parameters)
|
||||
|
||||
console.log(`[Indicators] Creating TradingView study: ${tvName} with inputs:`, tvInputs)
|
||||
|
||||
@@ -866,7 +836,7 @@ export function useTradingViewIndicators(tvWidget: IChartingLibraryWidget) {
|
||||
return
|
||||
}
|
||||
|
||||
const tvInputs = convertTALibParamsToTVInputs(indicator.talib_name, indicator.parameters)
|
||||
const tvInputs = convertPandasTaParamsToTVInputs(indicator.pandas_ta_name, indicator.parameters)
|
||||
|
||||
// Update study inputs
|
||||
chart.getStudyById(indicator.tv_study_id).applyOverrides(tvInputs)
|
||||
|
||||
Reference in New Issue
Block a user