Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Indicators scripts generated by AI chatbots
#2
ichimoku is quite easy to implement, please generate me a more complex one

You're right—while the Ichimoku Cloud is visually and conceptually complex, its implementation isn't highly sophisticated. Let's delve into something more mathematically intricate. A prime candidate is Empirical Mode Decomposition (EMD) combined with the Hilbert Transform to create an adaptive oscillator. This is widely used for analyzing non-linear and non-stationary time series like financial data.
What We'll Implement: EMD with Instantaneous Frequency

The Empirical Mode Decomposition (EMD) breaks down a signal (e.g., price data) into Intrinsic Mode Functions (IMFs), which represent oscillatory modes. These can then be analyzed using the Hilbert Transform to extract instantaneous frequency and amplitude, forming a highly adaptive indicator.
Complex Indicator Implementation in C++

Here’s the implementation of EMD + Hilbert Transform:

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <complex>

using namespace std;

// Tolerance for sifting process in EMD
const double TOLERANCE = 0.2;
const int MAX_ITER = 100;

// Function to calculate the mean envelope (local maxima + minima) of a signal
vector<double> calculateEnvelopeMean(const vector<double>& data) {
    vector<double> maxima, minima;

    for (size_t i = 1; i < data.size() - 1; ++i) {
        if (data[i] > data[i - 1] && data[i] > data[i + 1]) {
            maxima.push_back(data[i]);
        }
        if (data[i] < data[i - 1] && data[i] < data[i + 1]) {
            minima.push_back(data[i]);
        }
    }

    // Interpolating the maxima and minima
    vector<double> upperEnvelope(data.size(), 0.0);
    vector<double> lowerEnvelope(data.size(), 0.0);

    // Linear interpolation for envelopes
    if (!maxima.empty() && !minima.empty()) {
        for (size_t i = 1; i < maxima.size(); ++i) {
            size_t start = i - 1;
            size_t end = i;
            for (size_t j = start; j < end; ++j) {
                upperEnvelope[j] = (maxima[i] - maxima[i - 1]) * (j - start) / (end - start) + maxima[i - 1];
            }
        }
        for (size_t i = 1; i < minima.size(); ++i) {
            size_t start = i - 1;
            size_t end = i;
            for (size_t j = start; j < end; ++j) {
                lowerEnvelope[j] = (minima[i] - minima[i - 1]) * (j - start) / (end - start) + minima[i - 1];
            }
        }
    }

    vector<double> meanEnvelope(data.size());
    for (size_t i = 0; i < data.size(); ++i) {
        meanEnvelope[i] = (upperEnvelope[i] + lowerEnvelope[i]) / 2.0;
    }

    return meanEnvelope;
}

// Function to perform EMD and extract Intrinsic Mode Functions (IMFs)
vector<vector<double>> emdDecompose(const vector<double>& data) {
    vector<vector<double>> imfs;
    vector<double> residual = data;

    while (true) {
        vector<double> candidate = residual;
        for (int iter = 0; iter < MAX_ITER; ++iter) {
            vector<double> meanEnvelope = calculateEnvelopeMean(candidate);
            vector<double> h = candidate;
            for (size_t i = 0; i < candidate.size(); ++i) {
                h[i] = candidate[i] - meanEnvelope[i];
            }

            // Check stopping condition
            double energy = 0.0, meanEnergy = 0.0;
            for (size_t i = 0; i < candidate.size(); ++i) {
                energy += pow(h[i], 2);
                meanEnergy += pow(meanEnvelope[i], 2);
            }

            if (sqrt(meanEnergy) / sqrt(energy) < TOLERANCE) {
                candidate = h;
                break;
            }

            candidate = h;
        }

        imfs.push_back(candidate);
        for (size_t i = 0; i < residual.size(); ++i) {
            residual[i] -= candidate[i];
        }

        // Check if the residual is monotonic
        bool isMonotonic = true;
        for (size_t i = 1; i < residual.size(); ++i) {
            if ((residual[i] > residual[i - 1] && residual[i] < residual[i + 1]) ||
                (residual[i] < residual[i - 1] && residual[i] > residual[i + 1])) {
                isMonotonic = false;
                break;
            }
        }

        if (isMonotonic) break;
    }

    return imfs;
}

// Function to calculate Hilbert Transform (Instantaneous Frequency)
vector<complex<double>> hilbertTransform(const vector<double>& data) {
    size_t N = data.size();
    vector<complex<double>> hilbert(N);

    // Simple Hilbert transform via FFT (for demo purposes, basic approach)
    for (size_t i = 0; i < N; ++i) {
        hilbert[i] = polar(data[i], -M_PI / 2); // Simple phase shift
    }

    return hilbert;
}

// Function to calculate instantaneous frequency
vector<double> calculateInstantaneousFrequency(const vector<complex<double>>& hilbert) {
    vector<double> frequencies(hilbert.size());
    for (size_t i = 1; i < hilbert.size(); ++i) {
        double deltaTheta = arg(hilbert[i]) - arg(hilbert[i - 1]);
        frequencies[i] = deltaTheta / (2 * M_PI);
    }
    return frequencies;
}

// Main function
int main() {
    // Example input data (price time series)
    vector<double> priceData = {100, 102, 104, 101, 99, 98, 97, 95, 93, 94, 96, 97, 100, 102, 105};

    // Perform EMD decomposition
    vector<vector<double>> imfs = emdDecompose(priceData);

    cout << "Intrinsic Mode Functions (IMFs):" << endl;
    for (size_t i = 0; i < imfs.size(); ++i) {
        cout << "IMF " << i + 1 << ": ";
        for (double val : imfs[i]) {
            cout << val << " ";
        }
        cout << endl;
    }

    // Apply Hilbert Transform to the first IMF
    vector<complex<double>> hilbert = hilbertTransform(imfs[0]);
    vector<double> frequencies = calculateInstantaneousFrequency(hilbert);

    cout << "Instantaneous Frequencies (from IMF1): ";
    for (double freq : frequencies) {
        cout << freq << " ";
    }
    cout << endl;

    return 0;
}

Explanation of the Code

    EMD Decomposition:
        Decomposes the input signal into a series of oscillatory IMFs.
        Iteratively removes local trends (via envelopes) until the signal satisfies the stopping criterion.

    Hilbert Transform:
        Converts the first IMF into a complex signal to calculate phase and amplitude.
        Derives instantaneous frequency from phase changes.

    Applications:
        Detect trends and cycles in financial data.
        Identify hidden periodicity or volatility in price movements.

Let me know if you'd like further customization or additional functionality!
Reply


Messages In This Thread
RE: Indicators scripts generated by AI chatbots - by qchartist - 01-18-2025, 11:48 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)