package com.jbooktrader.indicator.velocity;

import jama.*;
import jkalman.*;

import com.jbooktrader.platform.indicator.*;
import com.jbooktrader.platform.marketbook.*;

/**
 * Tension of limit order book balance in relation to price
 */
public class TensionKalman extends Indicator {
	private double fastBalance, slowBalance, fastPrice, slowPrice;
	private final JKalman kalmanFastPrice, kalmanSlowPrice;
	private final JKalman kalmanFastBalance, kalmanSlowBalance;
    private int counter;

    public TensionKalman(int fastNoise, int slowNoise) {
		super(fastNoise, slowNoise);

		kalmanFastPrice = getInstance(fastNoise / 100.0);
		kalmanSlowPrice = getInstance(slowNoise / 100.0);

		kalmanFastBalance = getInstance(fastNoise / 100.0);
		kalmanSlowBalance = getInstance(slowNoise / 100.0);
	}

	private JKalman getInstance(double noise) {
		try {
			JKalman kalman = new JKalman(1, 1);
			kalman.setTransition_matrix(Matrix.identity(1, 1));
			kalman.setMeasurement_noise_cov(Matrix.identity(1, 1, noise));
			kalman.setError_cov_post(kalman.getError_cov_post().identity());
			return kalman;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private double getPostState(JKalman kalman, double measurement) {
		kalman.Predict();
		Matrix m = new Matrix(1, 1);
		m.set(0, 0, measurement);
		kalman.Correct(m);
		return kalman.getState_post().get(0, 0);
	}

	@Override
	public void calculate() {
        counter++;
        MarketSnapshot snapshot = marketBook.getSnapshot();

		// balance
		double balance = snapshot.getBalance();
		fastBalance = getPostState(kalmanFastBalance, balance);
		slowBalance = getPostState(kalmanSlowBalance, balance);
		double balanceVelocity = fastBalance - slowBalance;

		// price
		double price = snapshot.getPrice();
		fastPrice = getPostState(kalmanFastPrice, price);
		slowPrice = getPostState(kalmanSlowPrice, price);
		double priceVelocity = 2 * (fastPrice - slowPrice);

        // tension
        if (counter > 3600) { // let the filter settle for 1 hour
		    value = balanceVelocity - priceVelocity;
        }
    }

	@Override
	public void reset() {
		fastBalance = slowBalance = value = counter = 0;
		fastPrice = slowPrice = marketBook.getSnapshot().getPrice();
	}
}
