/*
 * 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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.strategyquant.lib.results.SQOrder;
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.utils.SQUtils;

public class DrawdownValues extends StatValue {
	public static final Logger Log = LoggerFactory.getLogger("DrawdownValues");

	@Override
	public String dependsOn() {
		return StatsConst.join(StatsConst.NET_PROFIT);
	}
	
	@Override
	public void initCompute(SQStats stats, StatsTypeCombination combination, SQOrderList ordersList, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
	}

	@Override
	public void computeForOrder(SQStats stats, StatsTypeCombination combination, SQOrder order, 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 {
		String plType = combination.getPLType();
		double initialCapital = settings.getDouble("InitialDeposit", 10000); 		

		//DrawdownComputer.computeDrawdown(initialCapital, ordersList);
		
		double peakEquity = initialCapital;
    	double peakPips = 0;
    	double peakPct = 0;
    	
    	double equityOnOrderStart;
    	double equityMoney = initialCapital;
    	double equityPips = 0;
    	double equityPct = 0;
    	
		double maxOpenDDMoney = 0;
    	double maxOpenDDPips = 0;
    	double maxOpenDDPct = 0;
    	
    	for(SQOrder order : ordersList) {
 		
    		equityOnOrderStart = equityMoney;
    		equityMoney += order.PL;
            equityPips += order.PipsPL;
            equityPct += order.PctPL;

            if(order.getMAE(SQConst.PL_IN_MONEY) < maxOpenDDMoney) maxOpenDDMoney =   order.getMAE(SQConst.PL_IN_MONEY);
            if(order.getMAE(SQConst.PL_IN_TICKS) < maxOpenDDPips) maxOpenDDPips =  order.getMAE(SQConst.PL_IN_TICKS);
            if(order.getMAE(SQConst.PL_IN_PCT) < maxOpenDDPct) maxOpenDDPct =  order.getMAE(SQConst.PL_IN_PCT);
            
            order.DD = specialSubtraction(peakEquity, equityMoney);
            
            // percentage DD is computed as % of current DD in money versus 
            // equity balance that was at the beginning of trade
           	order.PctDD = getPercentageDD(order.DD, peakEquity); //equityOnOrderStart);
            
            order.PipsDD =  specialSubtraction(peakPips, equityPips);
            
            if(combination.isFull()) {
            	//Log.info("XX "+order.Order+" "+SQTime.toDateMinuteString(order.OpenTime)+" : "+order.PL+", equityOnOrderStart: "+equityOnOrderStart +", DD: "+order.DD);
            }
            
            if(equityMoney > peakEquity) {
            	peakEquity = equityMoney;
            }
            if(equityPips > peakPips) {
            	peakPips = equityPips;
            }
            if(equityPct > peakPct) {
            	peakPct = equityPct;
            }
    	}		

		double maxDD = 99999999;
		double maxPctDD = 99999999;
		double maxPipsDD = 99999999;
    	double actualDD = 0;

		// Note - drawdown in orders is negative ($ -1234), but drawdown returned 
		// in stats values should be positive ($ 1234)

		for(SQOrder order : ordersList) {			
			if(order.DD < maxDD) maxDD = order.DD;
			if(order.PctDD < maxPctDD) maxPctDD = order.PctDD;
			if(order.PipsDD < maxPipsDD) maxPipsDD = order.PipsDD;
			
			actualDD = order.DD;
		}
		
		stats.set(StatsConst.ACTUAL_DD, SQUtils.round2(Math.abs(actualDD)));
		stats.set(StatsConst.DRAWDOWN, SQUtils.round2(Math.abs(maxDD)));
		stats.set(StatsConst.PCT_DRAWDOWN, SQUtils.round2(Math.abs(maxPctDD)));
		stats.set(StatsConst.PIPS_DRAWDOWN, SQUtils.round2(Math.abs(maxPipsDD)));

		stats.set(StatsConst.MAX_OPEN_DD, SQUtils.round2(Math.abs(maxOpenDDMoney)));
		stats.set(StatsConst.PCT_MAX_OPEN_DD, SQUtils.round2(Math.abs(maxOpenDDPct)));
		stats.set(StatsConst.PIPS_MAX_OPEN_DD, SQUtils.round2(Math.abs(maxOpenDDPips)));
				
		String dd_key = plType.equals(SQConst.PL_IN_PCT) ? StatsConst.PCT_DRAWDOWN : (plType.equals(SQConst.PL_IN_TICKS) ? StatsConst.PIPS_DRAWDOWN : StatsConst.DRAWDOWN);
		double retDDRatio = SQUtils.safeDivide(stats.getDouble(StatsConst.NET_PROFIT), stats.getDouble(dd_key));
		stats.set(StatsConst.RETURN_DD_RATIO, SQUtils.round2(retDDRatio));
	}
	
	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;
	}  
	
	private static double getPercentageDD(double pl, double equity) {
		if(equity <= 0 || pl > equity) {
			return -1;
		}
	    	
		return pl / (equity / 100);
	}		
}