Overview
kScript v2 introduces user-defined functions, allowing you to encapsulate logic into reusable modules. Functions can accept both var and timeseries arguments, support both positional and named parameter calling (kwargs), and must follow specific scoping rules.
| Feature | Description |
|---|---|
func | Keyword used to define functions |
| Infinite Possibilities | Create any custom logic you need |
| Global Scope Required | Functions must be declared at top level |
Function Declaration
Basic Syntax
func functionName(parameter1, parameter2) {
// Function body
return result
}Kwargs Support
User-defined functions support both positional and named parameter calling conventions:
// Function definition
func calculate(base, multiplier, offset) {
return base * multiplier + offset
}
// Positional calling
var result1 = calculate(10, 2, 5) // Returns 25
// Named parameter calling (kwargs)
var result2 = calculate(base=10, multiplier=2, offset=5) // Returns 25
var result3 = calculate(offset=5, base=10, multiplier=2) // Returns 25Syntax Details
Function Name: Must follow standard identifier rules (letters, numbers, underscore). Cannot start with a number.
Parameters:
Can accept var and timeseries arguments. Parameter types are inferred from usage. Support both positional and named parameter calling (kwargs).
Return Statement: Functions must explicitly return a value. The return type is inferred from the returned expression.
Function Examples
Simple Calculation
Basic mathematical operations with error handling:
func safeDiv(a, b) {
return b == 0 ? 0 : a / b
}
// Usage
var result = safeDiv(a=10, b=2) // Returns 5
var safe = safeDiv(a=10, b=0) // Returns 0Average of Two Values
func calculateAverage(a, b) {
return (a + b) / 2
}
// Usage
var avg = calculateAverage(close[0], close[1])Custom Indicator Logic
func isGreenCandle(openPrice, closePrice) {
return closePrice > openPrice
}
func isBullishEngulfing(prevOpen, prevClose, currOpen, currClose) {
var prevWasRed = prevClose < prevOpen
var currIsGreen = currClose > currOpen
var engulfs = currOpen < prevClose && currClose > prevOpen
return prevWasRed && currIsGreen && engulfs
}
// Usage
timeseries ohlcv = ohlcv(symbol=currentSymbol, exchange=currentExchange)
var bullish = isBullishEngulfing(
prevOpen=ohlcv.open[1],
prevClose=ohlcv.close[1],
currOpen=ohlcv.open[0],
currClose=ohlcv.close[0]
)Constraints and Rules
No Timeseries Declarations Inside Functions
Functions cannot declare new timeseries inside their body. All timeseries must be declared in global scope.
// Invalid
func bad() {
timeseries ts = ohlcv(...) // Error!
}
// Valid - pass timeseries as parameter
func good(ts) {
return ts.close[0]
}Global Scope Only
Functions must be declared in global scope, not inside loops, conditionals, or other functions.
// Invalid
if (condition) {
func bad() {...} // Error!
}
// Valid
func good() {...}
if (condition) {
var result = good() // OK to call
}Parameter Types
Functions can accept var and timeseries arguments. Types are inferred from how parameters are used.
// Valid - accepts both var and timeseries
func processData(varParam, tsParam) {
var current = tsParam[0] // Treats tsParam as timeseries
return varParam + current
}Return Requirement
All functions must have an explicit return statement. The return type is inferred from the expression.
// Valid
func add(a, b) {
return a + b // Required
}
// Invalid - no return
func noReturn(a, b) {
var sum = a + b // Missing return!
}Best Practices
Each function should do one thing well:
// Good - single responsibility
func calculateRSIColor(rsiValue) {
return rsiValue > 70 ? 0 : (rsiValue < 30 ? 1 : 2)
}Function names should clearly indicate what they do:
// Good
func isOverbought(rsiValue) { return rsiValue > 70 }
func calculatePercentChange(oldValue, newValue) {...}Using named parameters makes function calls self-documenting:
// Self-documenting call
var signal = isBullishEngulfing(
prevOpen=ohlcv.open[1],
prevClose=ohlcv.close[1],
currOpen=ohlcv.open[0],
currClose=ohlcv.close[0]
)