Getting Started
kScript is a TypeScript-based domain-specific language designed for financial data analysis and visualization. It allows you to write scripts for technical analysis, trading indicators, and market data processing with a syntax similar to Pine Script but powered by modern web technologies.
No, you don't need to know TypeScript. kScript has its own simplified syntax. However, familiarity with programming concepts will help you write more complex scripts.
Data Sources and Context
These are built-in context variables that automatically contain the current trading pair and exchange being analyzed:
timeseries data = ohlcv(currentSymbol, currentExchange)
print("Analyzing:", currentSymbol, "on", currentExchange)kScript executes per-bar, meaning on each bar, only data up to that point is available. When you access historical data like data[5], the first 4 bars will return NaN because there aren't 5 bars of history yet.
Solution: Always check for NaN or ensure enough historical data exists before using it in calculations. You can use the barIndex to make sure you're not accessing data too early.
timeseries trade = ohlcv(currentSymbol, currentExchange)
// Accessing 5 bars back
print(trade[5])
// Output on bars 0-3: NaN (not enough history)
// Output on bar 4 onwards: actual data from 5 bars agoYes, but you need to explicitly specify each symbol:
timeseries btc_data = ohlcv("BTCUSDT", "BINANCE")
timeseries eth_data = ohlcv("ETHUSDT", "BINANCE")No, you cannot run a script without source data. kScript is designed for time-series analysis and requires data to create the timeline for bar-by-bar execution. Even if you declare sources but they return empty data, the script won't run because there are no bars to process.
// ✗ Won't produce any output
define("Empty Script", "onchart", true)
var value = 100
plotLine(value) // Never executes because there are no bars
// ✓ Correct - with data source
define("Working Script", "onchart", true)
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
var value = ohlcvData.close
plotLine(value) // Executes for each barNo, you cannot call source functions inside control structures. Source subscriptions must be declared at the root level of your script in timeseries declarations.
Why: Sources need to be fetched and prepared before the script can execute. The runtime extracts source calls during the initialization phase, before the bar-by-bar loop begins. Dynamic source subscription during control flow would require async operations that aren't supported.
// ✓ Correct - at root level
timeseries ohlcv = source("ohlcv", "BTCUSDT", "BINANCE")
// ✗ Wrong - inside control structure
if (someCondition) {
timeseries ohlcv = source("ohlcv", "BTCUSDT", "BINANCE") // Won't work
}Orderbook data is accessed through specialized built-in functions that operate on orderbook timeseries sources. The data structure is [timestamp, price1, amount1, price2, amount2, ...] where positive amounts are bids and negative amounts are asks.
Available functions:
sumBids(source, depthPct=10)- Sum of all bid amounts within depth percentagesumAsks(source, depthPct=10)- Sum of all ask amounts within depth percentagemaxBidAmount(source, depthPct=10)- Maximum bid amount within depthmaxAskAmount(source, depthPct=10)- Maximum ask amount within depthminBidAmount(source, depthPct=10)- Minimum bid amount within depthminAskAmount(source, depthPct=10)- Minimum ask amount within depth
timeseries orderbookData = source("orderbook", "BTCUSDT", "BINANCE")
var totalBids = sumBids(orderbookData, depthPct=5)
var totalAsks = sumAsks(orderbookData, depthPct=5)
var bidAskRatio = totalBids / totalAsks
plotLine(value=bidAskRatio, width=2, colors=["blue"], label=["Bid/Ask Ratio"], desc=["Bid Ask Ratio"])kScript fills data gaps with NaN values. The system creates a continuous timestamp array based on the interval, and when fetched data doesn't match the timeline length, gaps are pre-filled with NaN.
Important: For line plots, kScript will interpolate to connect points across gaps. For other use cases, if you need interpolation (forward fill, linear interpolation, etc.), you must implement it manually using custom logic.
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
static lastValue = 0
var currentValue = ohlcvData.close
if (isnan(currentValue)) {
currentValue = lastValue // Forward fill
} else {
lastValue = currentValue
}
plotLine(value=currentValue, width=2, colors=["blue"], label=["Current Value"], desc=["Current Value"])Technical Indicators
NaN (Not a Number) usually occurs when:
- There's insufficient historical data for the calculation
- You're dividing by zero
- The data source has gaps
Solution: Check for NaN values:
var safe_value = !isnan(sma_value) ? sma_value : 0Plotting and Visualization
plotLine(value=sma20, width=1, colors=["blue"], label=["SMA 20"], desc=["20-period Simple Moving Average"])
plotLine(value=sma50, width=2, colors=["red"], label=["SMA 50"], desc=["50-period Simple Moving Average"])Yes, use ternary operators or conditional values:
var buy_signal = crossover(sma_fast, sma_slow)
plotShape(value=buy_signal ? data.low : na, shape="circle", width=2, colors=["green"], label=["Buy Signal"], desc=["Buy Signal Marker"])Use the colorIndex parameter:
var trend = sma_fast > sma_slow ? 1 : 0
plotLine(value=data.close, width=2, colors=["red", "green"], colorIndex=trend, label=["Price"], desc=["Price with Dynamic Colors"])Conditionals (if-else): Yes - You can call plot functions inside if-else statements. The plot will execute conditionally based on the condition at each bar.
Loops: Not allowed - Plotting inside loops would create multiple plot outputs per bar, which is not the intended behavior and may cause unexpected results.
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// ✓ Allowed in conditionals
if (ohlcv.close > ohlcv.open) {
plotLine(value=ohlcvData.close, width=2, colors=["green"], label=["Bullish"], desc=["Bullish Price"])
} else {
plotLine(value=ohlcvData.close, width=2, colors=["red"], label=["Bearish"], desc=["Bearish Price"])
}
// ✗ Not recommended in loops
for (var i = 0; i < 10; i++) {
plotLine(value=i, width=1, colors=["blue"], label=["Loop"], desc=["Loop Value"]) // Creates multiple plots per bar
}There is NO functional difference. plot() with plotType="line" is simply an alias that internally calls plotLine(). The plot() function is a generic interface that can create different plot types by changing the plotType parameter.
Available plot types via plot():
plotType="line"or"spline"-> callsplotLine()plotType="bar"-> callsplotBar()plotType="candle"-> callsplotCandle()plotType="point"-> callsplotShape()
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// These three are identical
plotLine(value=ohlcvData.close, width=2, colors=["blue"], label=["Price"], desc=["Close Price"])
plot(value=ohlcvData.close, plotType="line", width=2, colors=["blue"], label=["Price"], desc=["Close Price"])
plot(value=ohlcvData.close, plotType="spline", width=2, colors=["blue"], label=["Price"], desc=["Close Price"])
// plot() can also create other types
plot(value=ohlcvData.close, plotType="bar", width=1, colors=["green"], label=["Volume"], desc=["Volume Bars"])
plot(value=[ohlcvData.open, ohlcvData.high, ohlcvData.low, ohlcvData.close], plotType="candle", width=1, colors=["red", "green"], label=["OHLC"], desc=["OHLC Candlestick"])Shape and text plots use a coordinate-based positioning system with price (y-axis) and time (x-axis):
- X-axis (Time): Automatically set to the current bar timestamp. For
plotRange(), you can specify custom timestamps fortime1andtime2. - Y-axis (Price): Explicitly provided as the
priceorvalueparameter. - Text alignment:
xAlignandyAlignparameters affect rendering relative to the anchor point.
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// Plot shape at high price
if (ohlcvData.close > ohlcvData.open) {
plotShape(value=ohlcvData.high, shape="circle", width=3, colors=["green"], label=["Bullish"], desc=["Bullish Signal"])
}
// Plot text at specific price level
plotText("Signal", "yellow", ohlcvData.close, size=12, fill=true, backgroundColor="black")
// Plot range between two points
var prevTime = time() - (60 * 60 * 1000) // 1 hour ago
plotRange(prevTime, ohlcvData.low, time(), ohlcvData.high, color="blue", fillColor="rgba(0,0,255,0.2)")Common Issues and Troubleshooting
Check:
- You have a proper
define()statement - You're plotting something with
plotLine(),plotBar(), etc. - Your data source is valid. Empty data sources can lead to empty charts.
- Check the Problem pop up for error messages

Make sure:
- Variables are declared before use
- Variable names are spelled correctly
- You're using proper scope (variables declared in functions are local)
Use print() and printTimeSeries() statements to output values:
print("Current price:", data.close)
print("SMA value:", sma_value)
printTimeSeries(data, priceIndex=4) // Print close pricesEnsure you're:
- Using timeseries data correctly
- Not using static calculations where dynamic ones are needed
- Plotting the results properly
No, using null will cause plot values to become 0 because the runtime's Number(null) returns 0, not NaN. This means your "empty" data points will plot as zero values instead of gaps.
Solution: Use NaN to represent missing data. The runtime properly handles NaN as missing data, and plot functions will show gaps where NaN values occur.
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// ✗ Wrong - null becomes 0
var value1 = isnan(ohlcvData.close) ? null : ohlcvData.close
plotLine(value1) // Will plot 0 for missing data
// ✓ Correct - use NaN
var value2 = isnan(ohlcvData.close) ? NaN : ohlcvData.close
plotLine(value2) // Will show gap for missing dataLanguage Features and Syntax
No, kScript v2 does NOT support switch statements. Only if-else conditionals and loops (for, while) are supported control structures.
Workaround: Use nested if-else chains to achieve similar functionality.
// ✗ Switch statements not supported
// switch (signal) {
// case "buy": ...
// case "sell": ...
// }
// ✓ Use if-else chains instead
if (signal == "buy") {
plotShape(value=data.low, shape="circle", width=2, colors=["green"], label=["Buy"], desc=["Buy Signal"])
} else if (signal == "sell") {
plotShape(value=data.high, shape="circle", width=2, colors=["red"], label=["Sell"], desc=["Sell Signal"])
} else if (signal == "hold") {
// Do nothing
} else {
// Default action
}Arrays: Partial support - Arrays are supported with type restrictions. Arrays must contain elements of the same type (homogeneous arrays).
Supported array types:
number[]- Array of numbersstring[]- Array of stringsany[]- Generic arrays (for mixed timeseries/number)
Objects: Very limited - Objects are treated as type any. Main use cases are input() constraints like {min: 0, max: 100} and accessing timeseries fields via member access like ohlcv.close. You cannot create custom objects with arbitrary properties.
// ✓ Homogeneous arrays
var colors = ["red", "green", "blue"]
var prices = [100, 200, 300]
// ✓ Array of timeseries values
var ohlc = [ohlcv.open, ohlcv.high, ohlcv.low, ohlcv.close]
plotCandle(value=ohlc, width=1, colors=["green", "red"], label=["OHLC"], desc=["OHLC Candlestick"])
// ✗ Mixed type arrays not allowed
var mixed = [100, "hello", true] // Error
// ✓ Object for constraints (limited support)
var userLength = input("Length", "number", defaultValue=14, constraints={min:1, max:100})No, kScript v2 does NOT currently support cross-script communication. Each script runs in isolation and cannot access data or signals from other scripts. Each script has its own runtime context, data manager, variable environment, and series storage.
Note: Cross-script communication will be added as a feature soon.
Workaround: Use shared data sources. Both scripts can subscribe to the same source data and process it independently. Alternatively, combine the logic of multiple indicators into a single script.
// ✗ Cannot access signals from other scripts
// var otherRSI = getScriptValue("RSI Indicator", "rsi") // Not supported
// ✓ Workaround: Combine logic in a single script
define("Combined Indicator + Strategy", "onchart", true)
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// Calculate indicator
var rsiData = rsi(ohlcvData.close, period=14)
// Use indicator for strategy
if (rsiData > 70) {
plotShape(value=ohlcvData.high, shape="circle", width=5, colors=["red"], label=["Overbought"], desc=["Overbought Signal"])
} else if (rsiData < 30) {
plotShape(value=ohlcvData.low, shape="circle", width=5, colors=["green"], label=["Oversold"], desc=["Oversold Signal"])
}
plotLine(value=rsiData, width=2, colors=["purple"], label=["RSI"], desc=["Relative Strength Index"])Yes and No, with important constraints:
Custom Functions:
- Timeseries CAN be passed as parameters to custom functions
- Inside functions, timeseries are automatically indexed at the current bar to get numeric values. However, the behavior will not be intended, as the timeseries will be treated as a single value. For example, OHLCV timeseries data will be treated as a singular open data value.
Control Structures:
- Timeseries cannot be declared inside control structures (if/for/while)
timeseries ohlcvData = source("ohlcv", "BTCUSDT", "BINANCE")
// Custom function with timeseries parameter
func calculateRange(data) {
var high = data.high
var low = data.low
return high - low
}
// Use in control structure
if (ohlcvData.close > ohlcvData.open) {
var range = calculateRange(ohlcvData)
plotLine(value=range, width=2, colors=["green"], label=["Range"], desc=["Price Range"])
} else {
plotLine(value=0, width=2, colors=["red"], label=["Zero"], desc=["Zero Line"])
}No, kScript does not currently support alerts. Alert functionality is yet to be implemented for kScripts.
No, kScript does not support trade execution. kScript is designed for analysis and visualization purposes only. You cannot place orders, execute trades, or interact with exchange APIs for trading directly from kScript.
Performance and Optimization
- Use
staticfor constants - Avoid redundant calculations
- Use built-in functions instead of custom implementations
- Limit historical data lookback when possible
// Good: Calculate once
static fibonacci_level = 0.618
// Avoid: Recalculating every bar
var fibonacci_level = 618 / 1000Common Error Messages
You're passing a regular variable to a function that expects timeseries data:
var number = 42
var sma_val = sma(number, 14) // Wrong: number is not timeseries
timeseries prices = ohlcv(currentSymbol, currentExchange)
var sma_val = sma(prices.close, 14) // CorrectStill Have Questions?
Can't find what you're looking for? We're here to help!
Join the discussion in #kscript-floor or check out the kScript Reference for more details.