package jforex.strategies;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Queue;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IOrder.State;

//if we use console, we need @RequiresFullAccess for JForex-API 2.6.38 with java versions > 1.6.0_26
@RequiresFullAccess
public class SimpleScalpingStrategy implements IStrategy {
	
	@Configurable("")
	public Instrument instrument = Instrument.EURUSD;	
	@Configurable("")
	public Period period = Period.FIVE_MINS;
	
	public double amount = 0.1;
	public int stopLossPips = 10;
	public int takeProfitPips = 3;
	IOrder ordreBuy, ordreSell = null;
	
	
	private IEngine engine;	
	private IHistory history;
	private IConsole console;
	
	private Queue<IOrder> justFilledOrders = new ConcurrentLinkedQueue<IOrder>();
	
	//for logging
	@SuppressWarnings("serial")
	public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") {
		{
			setTimeZone(TimeZone.getTimeZone("GMT"));
		}
	};
	
	public void onStart(IContext context) throws JFException {
		this.engine = context.getEngine();		
		this.history = context.getHistory();
		this.console = context.getConsole();
   	}

	public void onAccount(IAccount account) throws JFException {
	}

	public void onMessage(IMessage message) throws JFException {
		//log messages to see what happens
		console.getOut().println(sdf.format(message.getCreationTime()) + " " +message);
		
		//in JForex-API 2.6.38 one can't change orders in onMessage, so we enqueue order change request and process it in next onTick
		if(message.getType() == IMessage.Type.ORDER_FILL_OK){
			justFilledOrders.add(message.getOrder());
		}
	}

	public void onStop() throws JFException {
	}

	public void onTick(Instrument instrument, ITick tick) throws JFException {	
		
    	//filter ticks
    	if(instrument != this.instrument){
    		return;
    	}
    	
    	//process just filled orders
    	while(!justFilledOrders.isEmpty()){
    		IOrder order = justFilledOrders.poll();
    		if(ordreBuy == order){
    			ordreBuy.setStopLossPrice(ordreBuy.getOpenPrice()-stopLossPips * instrument.getPipValue());
    			ordreBuy.setTakeProfitPrice(ordreBuy.getOpenPrice()+takeProfitPips * instrument.getPipValue());
    		}
    		if(ordreSell == order){
    			ordreSell.setStopLossPrice(ordreSell.getOpenPrice()+stopLossPips * instrument.getPipValue());
    			ordreSell.setTakeProfitPrice(ordreSell.getOpenPrice()+takeProfitPips * instrument.getPipValue());
    		}
    	}
	}
	
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar)throws JFException {  
    	
    	//filter bars
    	if(period != this.period || instrument != this.instrument){
    		return;
    	}
    	
    	IBar prevBar = history.getBar(this.instrument, Period.FIVE_MINS, OfferSide.BID, 1); 
    	double haut = prevBar.getHigh();
    	double bas = prevBar.getLow();
    	double priceBUY = haut+0.00050;
    	double priceSELL = bas-0.00050;
    	List<IOrder> ordres = engine.getOrders();
		if(ordres.isEmpty()){
	    	ordreBuy = engine.submitOrder("BUYSTOP", Instrument.EURUSD, OrderCommand.BUYSTOP, amount, priceBUY);
	    	ordreSell = engine.submitOrder("SELLSTOP", Instrument.EURUSD, OrderCommand.SELLSTOP, amount, priceSELL);
		}
    	if(ordreBuy.getState() != null || ordreSell.getState() != null){
    		if(ordreBuy.getState() == State.OPENED){
    			ordreBuy.setOpenPrice(priceBUY);
    		}
    		if(ordreSell.getState() == State.OPENED){
    			ordreSell.setOpenPrice(priceSELL);
    		}
    		if(ordreBuy.getState() == State.FILLED && ordreSell.getState() == State.OPENED){
    			engine.getOrder("SELLSTOP").close();
    		}
    		if(ordreSell.getState() == State.FILLED && ordreBuy.getState() == State.OPENED){
    			engine.getOrder("BUYSTOP").close();
    		}
    	}
    }
    
}














