/*
 * 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 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.SQSettings;
import com.strategyquant.lib.utils.SQUtils;

public class AvgProfitValues extends StatValue {
	private double sumTrades, sumTradesInPct, sumTradesInMoney;
	private int numberOfLiveOrders;
	
	@Override
	public String dependsOn() {
		return StatsConst.join(StatsConst.NET_PROFIT, StatsConst.PCT_DRAWDOWN, StatsConst.GROSS_PROFIT, StatsConst.GROSS_LOSS, StatsConst.NUMBER_OF_PROFITS, StatsConst.NUMBER_OF_LOSSES,
				StatsConst.TOTAL_TRADING_DAYS, StatsConst.TOTAL_TRADING_MONTHS, StatsConst.TOTAL_TRADING_YEARS, StatsConst.AVG_TRADES_PER_MONTH, StatsConst.NUMBER_OF_TRADES);
	}

	@Override
	public void initCompute(SQStats stats, StatsTypeCombination combination, SQOrderList ordersList, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
		sumTrades = 0;
    	sumTradesInPct = 0;
    	sumTradesInMoney = 0;
    	numberOfLiveOrders = 0;
	}

	@Override
	public void computeForOrder(SQStats stats, StatsTypeCombination combination, SQOrder order, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
	    if(order.isFilledOrder() && order.isRealOrder()) {
	    	numberOfLiveOrders++;
	    }
		
		sumTrades +=  Math.abs(getPLByStatsType(order, combination));
		sumTradesInPct +=  order.PctPL_TWR;
		sumTradesInMoney += order.PL;
	}


	@Override
	public void endCompute(SQStats stats, StatsTypeCombination combination, SQOrderList ordersList, SQSettings settings, SQStats statsLong, SQStats statsShort) throws Exception {
		
		double netProfit = stats.getDouble(StatsConst.NET_PROFIT);
		double grossProfit = stats.getDouble(StatsConst.GROSS_PROFIT);
		double grossLoss = stats.getDouble(StatsConst.GROSS_LOSS);
		int countProfits = stats.getInt(StatsConst.NUMBER_OF_PROFITS);
		int countLosses = stats.getInt(StatsConst.NUMBER_OF_LOSSES);
		
		int totalDaysOfTrading = stats.getInt(StatsConst.TOTAL_TRADING_DAYS);
		int totalMonthsOfTrading = stats.getInt(StatsConst.TOTAL_TRADING_MONTHS);
		int totalYearsOfTrading = stats.getInt(StatsConst.TOTAL_TRADING_YEARS);
		
		double avgTradesPerMonth = stats.getDouble(StatsConst.AVG_TRADES_PER_MONTH);

		stats.set(StatsConst.TOTAL_TRADING_DAYS, totalDaysOfTrading);
				
		double avgProfitByDay = SQUtils.safeDivide(netProfit, totalDaysOfTrading);
		double avgProfitByMonth = SQUtils.safeDivide(netProfit, totalMonthsOfTrading);
		double avgProfitByYear = SQUtils.safeDivide(netProfit, numberOfLiveOrders)*avgTradesPerMonth*12f;
		
		stats.set(StatsConst.AVG_PROFIT_BY_DAY, SQUtils.round2(avgProfitByDay));
		stats.set(StatsConst.AVG_PROFIT_BY_MONTH, SQUtils.round2(avgProfitByMonth));
		stats.set(StatsConst.AVG_PROFIT_BY_YEAR, SQUtils.round2(avgProfitByYear));
		
		double avgTrade = SQUtils.safeDivide(sumTradesInMoney, numberOfLiveOrders);
		double avgWin = SQUtils.safeDivide(grossProfit, countProfits);
		double avgLoss = SQUtils.safeDivide(grossLoss, countLosses);
		
		stats.set(StatsConst.AVG_TRADE, SQUtils.round2(avgTrade));
		stats.set(StatsConst.AVG_WIN, SQUtils.round2(avgWin));
		stats.set(StatsConst.AVG_LOSS, SQUtils.round2(avgLoss));
		
		double payoutRatio = SQUtils.safeDivide(avgWin, Math.abs(avgLoss));
		stats.set(StatsConst.PAYOUT_RATIO, SQUtils.round2(payoutRatio));
		
		// average annual profit / max DD
		double maxPctDD = stats.getDouble(StatsConst.PCT_DRAWDOWN);

		double initialCapital = settings.getDouble("InitialDeposit");
		
		// CAGR formula:
		// http://www.investopedia.com/ask/answers/071014/what-formula-calculating-compound-annual-growth-rate-cagr-excel.asp
		double temp1 = (initialCapital+sumTradesInMoney) / initialCapital;
		double temp2 = 1/(double) totalYearsOfTrading;
		
		double CAGR = (Math.pow(temp1, temp2) - 1) * 100;
		
		stats.set(StatsConst.CAGR, SQUtils.round2(CAGR));		

		double aarDDRatio = SQUtils.safeDivide(CAGR, maxPctDD);
		
		stats.set(StatsConst.AAR_DD_RATIO, SQUtils.round2(aarDDRatio));		
	}


}