/*
 * 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.MoneyManagementTypes;

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

import com.strategyquant.futurelib.backtester.SymbolsTable;
import com.strategyquant.lib.language.L;
import com.strategyquant.lib.results.SQOrder;
import com.strategyquant.lib.results.SQOrderList;
import com.strategyquant.lib.snippets.MoneyManagementSim.MoneyManagementType;
import com.strategyquant.lib.utils.SQUtils;

public class RiskFixedAmount extends MoneyManagementType {
	public static final Logger Log = LoggerFactory.getLogger("RiskFixedAmount");
	
	private double mmRiskInMoney;
	private double mmLots;
	private double mmMaxLots;
	private double mmSL;
	
	public RiskFixedAmount() {
		setName(L.t("Risk fixed amount"));
		setNote(L.tHtml("<b>Risk fixed amount of money on every trade</b><br/>Strategy will risk a given amount of money for every trade.<br/><br/>This is a basic money management without compounding. It can be used to test real performance of strategies where Stop loss is based on volatility (ATR)."));
		
		addDoubleParameter("RiskInMoney", L.t("Risk in $"), 500d, 1d, 10000d, 10d, L.t("How much money will be risked in every trade?"));
		addIntParameter("StopLoss", L.t("StopLoss in pips"), 100, 0, 1000000, 10, L.t("If order doesn't have SL then this predefined StopLoss will be used to compute the correct trade size according to money management"));
		addDoubleParameter("Lots", L.t("Lots if no MM"), 1d, 0.01d, 1000000d, 0.1d, L.t("How many lots should be traded if we disable or cannot use Money Management - for example when computed trade size is 0"));
		addDoubleParameter("MaxLots", L.t("Maximum lots"), 5d, 0.01d, 1000000d, 0.1d, L.t("The biggest lot size allowed"));

		setFormatedName(L.t("Fixed amount: ${RiskInMoney}, {Lots} lots, {MaxLots} max. lots"));
	}
	
	@Override
	public void init(SQOrderList originalOrderList, SymbolsTable symbolsTable) throws Exception {
		mmRiskInMoney = this.getDoubleParameterValue("RiskInMoney");
		mmSL = this.getDoubleParameterValue("StopLoss");
		mmLots = this.getDoubleParameterValue("Lots");
		mmMaxLots = this.getDoubleParameterValue("MaxLots");
	}

	@Override
	public double computeTradeSize(SQOrder order, double tickSize, double pointValue) throws Exception {
		if(mmRiskInMoney < 0) {
			throw new Exception("Money management wasn't properly initialized. Call init() method before computing trade size!");
		}
		
		double tradeSize = 0;
		double orderSL;
		
		if(order.StopLoss != 0) {
			// SL for order is known
			// order.StopLoss is a price level, we have to get the difference between SL level and open price to get SLin pips/ticks
			orderSL = Math.abs(order.OpenPrice - order.StopLoss) / tickSize; 

		} else {
			// SL for order is not known
			orderSL = mmSL;
		}
		
		double slInMoney = orderSL * tickSize * pointValue;

		Log.info("maxSL * tickSize * pointValue = "+orderSL+" * "+tickSize+" * "+pointValue+" = "+slInMoney);

		tradeSize = mmRiskInMoney / slInMoney;
				
		// round computed trade size to give decimal points and cap it by maximum lots
		tradeSize = SQUtils.roundDown(tradeSize, getDecimals());
		if(tradeSize == 0 && order.Size != 0) {
			tradeSize = mmLots;
		}
		
		if(tradeSize > mmMaxLots) {
			tradeSize = mmMaxLots;
		}
		
		return tradeSize;
	}
}