Here is an example of how roundToPippette works on the spread by calculating only 0.1 increments
import java.math.BigDecimal;
import java.util.Stack;
import com.dukascopy.api.Configurable;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;
public class Grider_with_Spread_Control_Rounded_Decimal implements IStrategy {
private IEngine engine;
private IConsole console;
private int counter = 0;
private IHistory history;
private ITick previousTick = null;
private Stack<IOrder> buyOrdrs = new Stack<IOrder>();
private Stack<IOrder> sellOrdrs = new Stack<IOrder>();
@Configurable("Step pips")
public double step = 20;
@Configurable("Instrument")
public Instrument instrument = Instrument.EURUSD;
@Configurable("Slippage")
public double slippage = 0;
@Configurable("Amount")
public double amount = 0.1;
@Configurable("Max Spread To Open Trade")
public double spreadmax = 0.1;
@Override
public void onStart(IContext context) throws JFException {
this.console = context.getConsole();
this.engine = context.getEngine();
this.setHistory(context.getHistory());
}
@Override
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
if (instrument != this.instrument) {
return;
}
}
public void onTick(Instrument instrument, ITick tick) throws JFException {
double lastBidPrice = history.getLastTick(instrument).getBid();
double lastAskPrice = history.getLastTick(instrument).getAsk();
double spread = lastAskPrice - lastBidPrice;
if (instrument != this.instrument) {
return;
}
if (previousTick == null) {
previousTick = tick;
return;
}
if (tick.getBid() >= previousTick.getBid() + getPipPrice(step) && (roundToPippette(spread, instrument) <= getPipPrice(spreadmax))) {
if (!buyOrdrs.isEmpty()) {
closeOrder(buyOrdrs.pop());
} else {
sellOrdrs.push(submitOrder(OrderCommand.SELL, instrument));
}
previousTick = tick;
} else if (tick.getAsk() <= previousTick.getAsk() - getPipPrice(step) && (roundToPippette(spread, instrument) <= getPipPrice(spreadmax))) {
if (!sellOrdrs.isEmpty()) {
closeOrder(sellOrdrs.pop());
} else {
buyOrdrs.push(submitOrder(OrderCommand.BUY, instrument));
}
previousTick = tick;
}
}
private IOrder submitOrder(OrderCommand orderCmd, Instrument instrument) throws JFException {
return engine.submitOrder(getLabel(instrument), instrument, orderCmd, amount, 0, slippage, 0, 0);
}
private void closeOrder(IOrder order) throws JFException {
if (order != null && isActive(order)&&order.getProfitLossInPips() >= step) {
order.close();
}
}
private boolean isActive(IOrder order) throws JFException {
if (order != null && order.getState() != IOrder.State.CLOSED && order.getState() != IOrder.State.CREATED
&& order.getState() != IOrder.State.CANCELED) {
return true;
}
return false;
}
private double getPipPrice(double pips) {
return pips * this.instrument.getPipValue();
}
private String getLabel(Instrument instrument) {
String label = instrument.name();
label = label + (counter++);
label = label.toUpperCase();
return label;
}
public void onMessage(IMessage message) throws JFException {
print(message);
}
public void onAccount(IAccount account) throws JFException {
}
public void onStop() throws JFException {
}
private void print(Object o) {
console.getOut().println(o);
}
public IHistory getHistory() {
return history;
}
public void setHistory(IHistory history) {
this.history = history;
}
private static double roundToPippette(double amount, Instrument instrument) {
return round(amount, instrument.getPipScale() + 1);
}
private static double round(double amount, int decimalPlaces) {
return (new BigDecimal(amount)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}