package com.strategyquant.extend.MonteCarloValues;

import com.strategyquant.lib.fitness.FitnessFunction;
import com.strategyquant.lib.language.L;
import com.strategyquant.lib.snippets.MonteCarloSim.MCStatsConst;
import com.strategyquant.lib.snippets.MonteCarloSim.MCValueComputer;
import com.strategyquant.lib.snippets.MonteCarloSim.MonteCarloStatValues;
import com.strategyquant.lib.utils.SQUtils;

public class MCPctDD extends MCValueComputer {

	public MCPctDD() {
		super(MCStatsConst.PCT_DD, FitnessFunction.MINIMIZE);
		
		setColumnName(L.t("Max % DD"));		
		setColumnWidth(100);
		setTooltip(L.t("Maximum Percentage Drawdown (lower is better)"));
	}

	@Override
	protected double compute(MonteCarloStatValues statValues, double initialCapital, double[] orders, double avgTradesPerMonth) throws Exception {
		double DD;
		double maxPctDD = 99999999;
		double peakEquity = initialCapital;
    	double equityMoney = initialCapital;
    	
    	for(int i=0; i<orders.length; i++) {
    		double pl = orders[i];
    		
    		equityMoney += pl;
            
    		DD = specialSubtraction(peakEquity, equityMoney);
    		
            // percentage DD is computed as % of currentDD in money versus 
            // equity balance that was at the beginning of trade
           	double PctDD = getPercentageDD(DD, peakEquity);
            
           	if(PctDD < maxPctDD) maxPctDD = PctDD;
           	
            if(equityMoney > peakEquity) {
            	peakEquity = equityMoney;
            }
    	}	
    	
    	return Math.abs(maxPctDD);
	}

	//-------------------------------------------------------------------------------------

    /**
	 * computes DD as a percentage of current equity.
	 *
	 * @param pl the pl
	 * @param equity the equity
	 * @return the percentage dd
	 */
	private static double getPercentageDD(double pl, double equity) {
		if(equity <= 0 || pl > equity) {
			return -1;
		}
	    	
		return pl / (equity / 100);
	}	
	
	//-------------------------------------------------------------------------------------

    /**
	 * subtracts equity from peak & handles positive DD case.
	 *
	 * @param peak the peak
	 * @param equity the equity
	 * @return the double
	 */
	private static double specialSubtraction(double peak, double equity) {
		double dd = peak - equity;
			
		if(dd < 0) {
			// this means that current equity is bigger than last peak, 
			// so we are not in drawdown currently
			dd = 0;
		}
		
		// convert DD to negative number
		return -1 * dd;
	} 
	
	@Override
	public String formatValue(double value) {
		return SQUtils.d2(value)+" %";
	}
}