//@version=6
// (C) yaseenm237
library("MyLibrary")
// Declare an array to store historical data points (features).
// Each data point is an array of floats representing features.
var historicalFeatures = array.new<array<float>>(0)
// Declare an array to store the corresponding labels (1: long, -1: short, 0: neutral).
var historicalLabels = array.new<int>(0)
// @function getClassificationVote: Determines the majority vote from a given array of labels (e.g., from nearest neighbors).
// It takes an array of labels (typically from the 'k' nearest historical data points) and returns the most frequent label.
// @param labelsArray array<int>: An array containing the labels (1 for long, -1 for short, 0 for neutral) of the nearest neighbors.
// @returns int: The predicted classification: 1 for long, -1 for short, or 0 for neutral if there's a tie or no clear majority.
export function getClassificationVote(labelsArray) {
int longCount = 0
int shortCount = 0
int neutralCount = 0
// Count the occurrences of each label (long, short, neutral) within the provided labelsArray.
for i = 0 to array.size(labelsArray) - 1
int label = array.get(labelsArray, i)
if label == 1
longCount += 1
else if label == -1
shortCount += 1
else
neutralCount += 1
// Determine the majority vote based on the counts.
// If longCount is strictly greater than both shortCount and neutralCount, it's a long prediction.
if longCount \> shortCount and longCount \> neutralCount
1
// If shortCount is strictly greater than both longCount and neutralCount, it's a short prediction.
else if shortCount \> longCount and shortCount \> neutralCount
-1
// If neutralCount is strictly greater than both longCount and shortCount, it's a neutral prediction.
else if neutralCount \> longCount and neutralCount \> shortCount
0
// Handle tie-breaking scenarios:
// If there's a tie between long and short, or any other tie, or no clear majority, default to neutral (0).
// This conservative approach avoids making a biased prediction when the model is uncertain.
else
0
}
// @function calculateEuclideanDistance: Calculates the Euclidean distance between two data points.
// @param point1 array<float>: The first data point.
// @param point2 array<float>: The second data point.
// @returns float: The Euclidean distance between the two points.
export function calculateEuclideanDistance(point1, point2) {
float sumSquaredDifferences = 0.0
int size1 = array.size(point1)
int size2 = array.size(point2)
int minSize = math.min(size1, size2)
for i = 0 to minSize - 1
float diff = array.get(point1, i) - array.get(point2, i)
sumSquaredDifferences += diff \* diff
math.sqrt(sumSquaredDifferences)
}
// @function findNearestNeighbors: Finds the indices of the 'k' nearest neighbors to a new data point.
// @param newPoint array<float>: The data point for which to find neighbors.
// @param historicalFeatures array<array<float>>: The array of historical data points (features).
// @param historicalLabels array<int>: The array of historical labels (used for indexing, not distance).
// @param k int: The number of nearest neighbors to find.
// @returns array<int>: An array containing the indices of the k nearest neighbors in the historical data.
export function findNearestNeighbors(newPoint, historicalFeatures, historicalLabels, k) {
// Array to store pairs of \[distance, index\]
var distancesWithIndices = array.new\<array\<float\>\>(0)
// Calculate distances to all historical data points and store with their indices
for i = 0 to array.size(historicalFeatures) - 1
array\<float\> historicalPoint = array.get(historicalFeatures, i)
float dist = calculateEuclideanDistance(newPoint, historicalPoint)
array.push(distancesWithIndices, array.new\<float\>(\[dist, float(i)\]))
// Sort the array based on distances (the first element of each inner array)
array.sort(distancesWithIndices, direction.asc)
// Get the indices of the k nearest neighbors
var nearestNeighborIndices = array.new\<int\>(0)
for i = 0 to math.min(k, array.size(distancesWithIndices)) - 1
array\<float\> distanceAndIndex = array.get(distancesWithIndices, i)
int index = int(array.get(distanceAndIndex, 1))
array.push(nearestNeighborIndices, index)
nearestNeighborIndices
}
// @function getNeighborLabels: Retrieves the labels of the nearest neighbors given their indices.
// @param nearestNeighborIndices array<int>: An array of indices of the nearest neighbors.
// @param historicalLabels array<int>: The array of historical labels.
// @returns array<int>: An array containing the labels of the nearest neighbors.
export function getNeighborLabels(nearestNeighborIndices, historicalLabels) {
// Initialize an empty array to store the neighbor labels.
var neighborLabels = array.new\<int\>(0)
// Iterate through the array of nearest neighbor indices.
for i = 0 to array.size(nearestNeighborIndices) - 1
// Get the index of the current nearest neighbor.
int neighborIndex = array.get(nearestNeighborIndices, i)
// Access the corresponding label from the historicalLabels array using the index.
int neighborLabel = array.get(historicalLabels, neighborIndex)
// Add the retrieved label to the array of neighbor labels.
array.push(neighborLabels, neighborLabel)
// Return the array containing the labels of the nearest neighbors.
neighborLabels
}
// @function performKNNClassification: Performs K-Nearest Neighbors classification for a new data point.
// @param newPoint array<float>: The data point to classify.
// @param historicalFeatures array<array<float>>: The historical data points (features).
// @param historicalLabels array<int>: The historical labels.
// @param k int: The number of neighbors to consider.
// @returns int: The predicted classification (1 for long, -1 for short, 0 for neutral).
export function performKNNClassification(newPoint, historicalFeatures, historicalLabels, k) {
// Find the indices of the k nearest neighbors.
array\<int\> nearestNeighborIndices = findNearestNeighbors(newPoint, historicalFeatures, historicalLabels, k)
// Get the labels of the nearest neighbors.
array\<int\> neighborLabels = getNeighborLabels(nearestNeighborIndices, historicalLabels)
// Get the classification vote from the neighbor labels.
int predic
tedClassification = getClassificationVote(neighborLabels)
// Return the predicted classification.
predictedClassification
}