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 java.awt.Color;
import java.text.DecimalFormat;
import com.dukascopy.api.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.TimeZone;
 
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 PendingStrategyMATRV100 implements IStrategy {
    
   @Configurable("Instrument")
   public Instrument instrument = Instrument.EURUSD;   
   @Configurable("Period")
   public Period period = Period.FIVE_MINS;
   @Configurable("Distance Pip")
   public int Distance = 11;
   @Configurable("StopLoss")
   public int stopLossPips = 50;   
   @Configurable("TakeProfit")
   public int takeProfitPips = 15;                    
   @Configurable("Lots Size")
   public double amount = 0.1;
   @Configurable("Moving Average")
   public int Period_MA = 50;

   IOrder ordreBuy, ordreSell = null;
    
        private IContext context = null;
        private IEngine engine = null;      
        private IHistory history = null;
        private IConsole console = null;
        private IIndicators indicators = null;
        public IAccount acc = null; 
   

   public double pip;    
   
   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.context = context;        
      this.engine = context.getEngine();      
      this.history = context.getHistory();
      this.console = context.getConsole();
      this.indicators = context.getIndicators();      
      }
 
   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 { 
    
    //----------------------------------------
       pip = instrument.getPipValue();
 
       //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*pip);
             ordreBuy.setTakeProfitPrice(ordreBuy.getOpenPrice()+takeProfitPips*pip);
          }
          if(ordreSell == order){
             ordreSell.setStopLossPrice(ordreSell.getOpenPrice()+stopLossPips*pip);
             ordreSell.setTakeProfitPrice(ordreSell.getOpenPrice()-takeProfitPips*pip);
          }
       }
   }
    
    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, OfferSide.BID, 1);
       double MA = indicators.ma(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, Period_MA, IIndicators.MaType.EMA, 0);
  
       double Max = prevBar.getHigh();
       double Min = prevBar.getLow();
       double priceBUY  = MA-Distance*pip;
       double priceSELL = MA+Distance*pip;
       
       List<IOrder> ordres = engine.getOrders();
      if(ordres.isEmpty()){
          ordreBuy = engine.submitOrder("BUYLimit", instrument, OrderCommand.BUYLIMIT, amount, priceBUY);
          ordreSell = engine.submitOrder("SELLLimit", instrument, OrderCommand.SELLLIMIT, 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("SELLLimit").close();
          }
          if(ordreSell.getState() == State.FILLED && ordreBuy.getState() == State.OPENED){
             engine.getOrder("BUYLimit").close();
          }
       }
    }
}