/*
 * Copyright (c) 2015, StrategyQuant - All rights reserved.
 *
 * Code in this file was made in a good faith that it is correct and does what it should. 
 * If you found a bug in this code OR you have an improvement suggestion OR you want to include 
 * your own code snippet into our standard library please contact us at:
 * http://tasks.strategyquant.com/projects/snippets/
 *
 * This code can be used only within StrategyQuant products. 
 * Every owner of valid (free, trial or commercial) license of any StrategyQuant product 
 * is allowed to freely use, copy, modify or make derivative work of this code without limitations,
 * to be used in all StrategyQuant products and share his/her modifications or derivative work 
 * with the StrategyQuant community.
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES 
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *  
 */
package com.strategyquant.extend.StatValues;

import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.strategyquant.gui.charts.equitychart.ChartData;
import com.strategyquant.lib.computers.DailyEquityComputer;
import com.strategyquant.lib.results.SQOrderList;
import com.strategyquant.lib.results.SQStats;
import com.strategyquant.lib.results.StatValue;
import com.strategyquant.lib.results.StatsConst;
import com.strategyquant.lib.results.StatsTypeCombination;
import com.strategyquant.lib.settings.SQConst;
import com.strategyquant.lib.settings.SQSettings;
import com.strategyquant.lib.snippets.CorrelationComputer;

/**
 * Stability is computed as R-Squared^2 between equity in time, and line created from first to last trade
 * R-Squared algorithm is as same as for RSQ Excel function, which itself is CORREL^2
 * So Stability = CORREL^4
 * 
 * @author Mark Fric
 *
 */
public class StabilityValues extends StatValue {
	public static final Logger Log = LoggerFactory.getLogger("StabilityValues");
	
	public static final double ERROR_VALUE = -99d;
	
    private double[] trades;
    private double[] line;
	
	@Override
	public void initCompute(SQStats stats, StatsTypeCombination combination, SQOrderList ordersList, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
	}	
	
	@Override
	public void endCompute(SQStats stats, StatsTypeCombination combination, SQOrderList ordersList, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
        try {	        
        	if(ordersList==null || ordersList.isEmpty()) {
        		stats.set(StatsConst.STABILITY, 0d);
        		
        		return;
        	}
        	
        	// we need to do:
	        // array of trades should be computed as same as for equity chart in Time mode - for every day there should be a size of equity
	        // array of line values should be the value of line (started at first trade, ended at last trade) computed for every day  
        	
	        this.trades = getDailyEquity(ordersList);
	        this.line = getLineValues(trades);
			
	        CorrelationComputer CorrelationComputer = new CorrelationComputer();
	        double correl =  CorrelationComputer.calculateCorrelation(this.trades, this.line);
	        		
	        this.trades = null;
	        this.line = null;
	        
	        stats.set(StatsConst.STABILITY, Math.pow(correl, 4));
        } catch(Exception e) {
			Log.error("Exc.", e);
			
			stats.set(StatsConst.STABILITY, ERROR_VALUE);
        }
	}


	private double[] getLineValues(double[] trades) {
		double[] line = new double[trades.length];
		
		double y1 = trades[0];
		double y2 = trades[trades.length-1];

		for(int i=0; i<trades.length; i++) {
			line[i] = getLineValue(i, 0, y1, trades.length, y2);
		}
				
		return line;
	}
	
	private static double getLineValue(double x, double x1, double y1, double x2, double y2) {
		return y1 + ((y2 - y1) / (x2 - x1))*(x - x1);
	}
	
	public double[] getDailyEquity(SQOrderList ordersList) {
		DailyEquityComputer computer = new DailyEquityComputer();
		ArrayList<ChartData> dailyEquityList = computer.computeDailyEquity(ordersList, SQConst.PL_IN_MONEY, SQConst.TRADE_PERIOD_CLOSE_TIME);
		
		double[] dailyEquity = new double[dailyEquityList.size()];
		
		for(int i=0; i<dailyEquityList.size(); i++) {
			dailyEquity[i] = dailyEquityList.get(i).yValue;
		}
		
		dailyEquityList = null;
		
		return dailyEquity;
	}

}