FAQ

General FAQ

Frequently asked questions about kScript, covering everything from basic syntax to advanced topics.

FAQ 5 min read

Getting Started

Data Sources and Context

These are built-in context variables that automatically contain the current trading pair and exchange being analyzed:

Context Variables
timeseries data = ohlcv(currentSymbol, currentExchange)
print("Analyzing:", currentSymbol, "on", currentExchange)


{% endfaqitem %}



{% faqitem question="Why do I get NaN when accessing historical data in early bars?" %}


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.
Historical NaN
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 ago


{% endfaqitem %}



{% faqitem question="Can I analyze multiple symbols in one script?" %}


Yes, but you need to explicitly specify each symbol:
Multiple Symbols
timeseries btc_data = ohlcv("BTCUSDT", "BINANCE")
timeseries eth_data = ohlcv("ETHUSDT", "BINANCE")


{% endfaqitem %}



{% faqitem question="Can I write a script without source data?" %}


**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.
Script Without Source Data
// ✗ 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 bar


{% endfaqitem %}



{% faqitem question="Can I subscribe to sources inside control structures (if/while/for)?" %}


**No**, 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.
Source Calls in Control Structures
// ✓ 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
}


{% endfaqitem %}



{% faqitem question="How do I access orderbook heatmap raw data?" %}


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 percentage
  • sumAsks(source, depthPct=10) - Sum of all ask amounts within depth percentage
  • maxBidAmount(source, depthPct=10) - Maximum bid amount within depth
  • maxAskAmount(source, depthPct=10) - Maximum ask amount within depth
  • minBidAmount(source, depthPct=10) - Minimum bid amount within depth
  • minAskAmount(source, depthPct=10) - Minimum ask amount within depth
Orderbook Access
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"])


{% endfaqitem %}



{% faqitem question="How does kScript handle data gaps and interpolation?" %}


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.
Data Gaps and Interpolation
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"])


{% endfaqitem %}


{% endfaqgroup %}

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:

NaN Handling
var safe_value = !isnan(sma_value) ? sma_value : 0


{% endfaqitem %}


{% endfaqgroup %}

Plotting and Visualization

Multiple Plots
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"])


{% endfaqitem %}



{% faqitem question="Can I plot conditional signals?" %}


Yes, use ternary operators or conditional values:
Conditional Plot
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"])


{% endfaqitem %}



{% faqitem question="How do I change plot colors dynamically?" %}


Use the `colorIndex` parameter:
Dynamic Colors
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"])


{% endfaqitem %}



{% faqitem question="Can I call plot functions inside conditionals (if-else) or loops?" %}


**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.
Plot Calls in Conditionals and Loops
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
}


{% endfaqitem %}



{% faqitem question='Difference between plotLine() and plot(plotType="line")?' %}


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" -> calls plotLine()
  • plotType="bar" -> calls plotBar()
  • plotType="candle" -> calls plotCandle()
  • plotType="point" -> calls plotShape()
plotLine() vs plot()
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"])


{% endfaqitem %}



{% faqitem question="How does the positioning system work for shape and text plots?" %}


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 for time1 and time2.
  • Y-axis (Price): Explicitly provided as the price or value parameter.
  • Text alignment: xAlign and yAlign parameters affect rendering relative to the anchor point.
Shape and Text Positioning
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)")


{% endfaqitem %}


{% endfaqgroup %}

Common Issues and Troubleshooting

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.

Null vs NaN
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 data


{% endfaqitem %}


{% endfaqgroup %}

Language Features and Syntax

Yes, since v3. switch is first-match with no fallthrough (no break needed): see control flow.

Switch (v3)
switch (signal) {
  case "buy": {
    plotShape(value=data.low, shape="arrowUp", location="belowBar", colors=["#16a34a"])
  }
  case "sell": {
    plotShape(value=data.high, shape="arrowDown", location="aboveBar", colors=["#dc2626"])
  }
  default: {
    // no-op
  }
}

`if-else` chains remain fully supported:
Equivalent if-else

// ✓ 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
}


{% endfaqitem %}



{% faqitem question="Are objects and arrays supported in kScript?" %}


**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 numbers
  • string[] - Array of strings
  • any[] - Generic arrays (for mixed timeseries/number)

Objects: full support since v3 via user-defined types and maps. Declare a struct with type, construct with TypeName.new(...), and store structs in collections: see user-defined types and collections. Anonymous {...} literals remain limited to specific call options (e.g. input() constraints and drawing opts).

Structs (v3)
type Zone { top: number, bottom: number, touches: number }
persist zones = []
zones.push(Zone.new(top=high, bottom=low, touches=0))
Arrays and Objects
// ✓ 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})


{% endfaqitem %}



{% faqitem question="Can a script get signals from another script or indicator?" %}


**No**, kScript v3 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.
Cross-Script Signals
// ✗ 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"])


{% endfaqitem %}



{% faqitem question="Can I use timeseries in custom functions and control structures?" %}


**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 in Custom Functions
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"])
}


{% endfaqitem %}



{% faqitem question="Does kScript support alerts?" %}


**No**, kScript does not currently support alerts. Alert functionality is yet to be implemented for kScripts.

{% endfaqitem %}



{% faqitem question="Can trades be executed from kScript?" %}


**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.

{% endfaqitem %}


{% endfaqgroup %}

Performance and Optimization

  • Use static for constants
  • Avoid redundant calculations
  • Use built-in functions instead of custom implementations
  • Limit historical data lookback when possible
Optimization
// Good: Calculate once
static fibonacci_level = 0.618

// Avoid: Recalculating every bar
var fibonacci_level = 618 / 1000


{% endfaqitem %}


{% endfaqgroup %}

Common Error Messages

You're passing a regular variable to a function that expects timeseries data:

Source Timeseries Error
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)  // Correct


{% endfaqitem %}


{% endfaqgroup %}

Still 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.