package dailyBot.model.dailyFx; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Vector; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import dailyBot.control.DailyExecutor; import dailyBot.control.DailyLog; import dailyBot.control.DailyLoopInfo; import dailyBot.control.DailyProperties; import dailyBot.control.DailyRunnable; import dailyBot.control.connection.dailyFx.DailyFxServerConnection; import dailyBot.model.Strategy; import dailyBot.model.Strategy.StrategyId; import dailyBot.model.StrategySignal; import dailyBot.model.StrategySystem; public class DailyFXStrategySystem extends StrategySystem { private boolean changed = false; protected Condition systemChanged = systemLock.newCondition(); public DailyFXStrategySystem() { strategies = new StrategyId[] { StrategyId.BREAKOUT1, StrategyId.BREAKOUT2, StrategyId.RANGE1, StrategyId.RANGE2, StrategyId.MOMENTUM1, StrategyId.MOMENTUM2 }; } @Override protected void checkConsistency() { for(StrategyId strategyId : strategies) if(strategyId.strategy() == null || strategyId.strategy().checkConsistency()) { DailyLog.logError("Error de consistencia en " + strategyId); strategyId.startStrategy(); } } @Override public void startThreads() { DailyRunnable monitorRunnable = new DailyRunnable("Monitor " + getClass().getCanonicalName(), 900000L, false) { public void runOnce() { try { DailyLoopInfo.registerLoop("DailyFX updater"); checkConsistency(); DailyLoopInfo.registerUpdate("DailyFX updater", "State", "reading from DailyFX server"); String[] read = DailyFxServerConnection.readDailyFxServer(); DailyLoopInfo.registerLoop("DailyFX updater last read string"); DailyLoopInfo.registerUpdate("DailyFX updater last read string", "Last read", Arrays.toString(read)); DailyLoopInfo.closeLoop("DailyFX updater last read string"); DailyLoopInfo.registerUpdate("DailyFX updater", "State", "readed without errors"); systemLock.lock(); try { DailyLoopInfo.registerUpdate("DailyFX updater", "State", "processing read data"); startProcessing(read); checkConsistency(); DailyLoopInfo.registerUpdate("DailyFX updater", "State", "data processed"); if(changed) systemChanged.signalAll(); } finally { systemLock.unlock(); } } catch(Exception e) { try { DailyLoopInfo.registerUpdate("DailyFX updater", "State", "error processing " + e + " " + e.getMessage()); if((errorCount.incrementAndGet() % 300) <= 1) DailyLog.logError(e.getMessage() + " Error en el ciclo dailyFX"); } catch(Exception e1) { DailyLog.logError(e.getMessage() + " Error en el ciclo de error DailyFX"); } } finally { DailyLoopInfo.closeLoop("DailyFX updater"); } } }; DailyExecutor.addRunnable(monitorRunnable, DailyProperties.isTesting() ? 10000 : 500, TimeUnit.MILLISECONDS, 3, TimeUnit.MINUTES); DailyRunnable persistenceRunnable = new DailyRunnable("Presistence " + getClass().getCanonicalName(), 600000L, false) { public void runOnce() { DailyLoopInfo.registerLoop("DailyFX persistence"); DailyLoopInfo.registerUpdate("DailyFX persistence", "State", "waiting for changes"); try { waitForChange(); DailyLoopInfo.registerUpdate("DailyFX persistence", "State", "stored in db"); } catch(RuntimeException e) { DailyLoopInfo.registerUpdate("DailyFX persistence", "State", "error storing " + e + " " + e.getMessage()); throw e; } finally { DailyLoopInfo.closeLoop("DailyFX persistence"); } } }; DailyExecutor.addRunnable(persistenceRunnable, 3, TimeUnit.MINUTES, 3, TimeUnit.MINUTES); } public static final AtomicReference <Vector <StrategySignal>> lastRead = new AtomicReference <Vector <StrategySignal>>(); public static final AtomicLong lastReadTime = new AtomicLong(); public static final AtomicLong lastChangeTime = new AtomicLong(); private static final AtomicLong errorCount = new AtomicLong(-1); @Override protected ArrayList <StrategySignal> read(String[] input) { try { DailyLoopInfo.registerUpdate("DailyFX updater", "Read state", "reading from DailyFX server"); ArrayList <StrategySignal> read = dailyJSON.leer(input[0]); DailyLoopInfo.registerUpdate("DailyFX updater", "Read state", "readed JSON without errors"); lastRead.set(new Vector <StrategySignal>(read)); lastReadTime.set(System.currentTimeMillis()); return read; } catch(Exception e) { DailyLoopInfo.registerUpdate("DailyFX updater", "Read state", "error reading JSON"); DailyLog.logError("Error leyendo las senales de DailyFX " + e.getMessage()); throw(new RuntimeException("Error de lectura")); } } @Override protected void process(String[] read) { try { ArrayList <StrategySignal> readSignals = read(read); DailyLoopInfo.registerUpdate("DailyFX updater", "Processing state", "processing readed signals"); DailyLoopInfo.registerLoop("DailyFX updater last read objects"); String readLog = ""; final int trailingStopHit = Integer.parseInt(DailyProperties .getProperty("dailyBot.model.dailyFx.DailyFXStrategySystem.trailingStopHit")); final int trailingStop = Integer.parseInt(DailyProperties .getProperty("dailyBot.model.dailyFx.DailyFXStrategySystem.trailingStop")); for(StrategySignal signal : readSignals) { DailyLoopInfo.registerUpdate("DailyFX updater", "Processing state current signal", "processing signal: " + signal); Strategy current = signal.getStrategyId().strategy(); StrategySignal affected = null; if((affected = current.hasPair(signal.getPair())) != null) { boolean changedInternal = false; if(signal.isBuy() != affected.isBuy()) { current .processSignalChange(signal.getPair(), true, false, affected.getLotNumber(), 0, affected); current.processSignalChange(signal.getPair(), false, signal.isBuy(), signal.getLotNumber(), affected.getEntryPrice(), affected); changed = true; changedInternal = true; lastChangeTime.set(System.currentTimeMillis()); if(current.getId() != StrategyId.BREAKOUT1) { DailyLog.addRangeInfo("cambios", "Cambio: " + affected + " por: " + signal); } } if(affected.getLotNumber() > signal.getLotNumber()) { current.processSignalChange(signal.getPair(), true, false, affected.getLotNumber() - signal.getLotNumber(), affected.getEntryPrice(), affected); if(affected.isBuy()) { if(affected.getStop() < affected.getEntryPrice()) affected.setStop(0d); } else { if(affected.getStop() > affected.getEntryPrice()) affected.setStop(0d); } changed = true; changedInternal = true; lastChangeTime.set(System.currentTimeMillis()); if(current.getId() != StrategyId.BREAKOUT1) { DailyLog.addRangeInfo("cambios", "Cambio: " + affected + " por: " + signal); } } else { int profit = affected.getPair().differenceInPips(affected.getEntryPrice(), affected.isBuy()); if(Math.abs(affected.getStop()) < 1e-4d) { affected.setStop(signal.getStop()); changed = true; changedInternal = true; } else { if(profit >= trailingStopHit) { double stop = affected.getPair().getCurrentPriceMinus(trailingStop, affected.isBuy()); if(affected.getPair().differenceInPips(stop, affected.getStop(), affected.isBuy()) > 0) { try { DailyLog.addRangeInfo("mejora stops", "Mejorando stop: " + affected + ", stop anterior: " + affected.getStop() + ", nuevo stop: " + stop); affected.setStop(stop); changed = true; changedInternal = true; } catch(Exception e) { DailyLog.logError("Zulutrade error: " + e.getMessage()); } } } } if(affected.isBuy()) { if(affected.getStop() < signal.getStop()) { affected.setStop(signal.getStop()); changed = true; changedInternal = true; } affected.changeStopDaily(signal.getStop()); } else { if(affected.getStop() > signal.getStop()) { affected.setStop(signal.getStop()); changed = true; changedInternal = true; } affected.changeStopDaily(signal.getStop()); } } if(!changedInternal) affected.setUniqueId("dailyfx-lastchecktime", System.currentTimeMillis()); readLog += "\n" + signal + "\n" + "found: " + affected + ", changed: " + changedInternal + "\n"; } else { readLog += "\n" + signal + "\n" + "not found, opening\n"; current.processSignalChange(signal.getPair(), false, signal.isBuy(), signal.getLotNumber(), signal.getEntryPrice(), affected); changed = true; lastChangeTime.set(System.currentTimeMillis()); if(current.getId() != StrategyId.BREAKOUT1) { DailyLog.addRangeInfo("cambios", "Agregando: " + signal); } } DailyLoopInfo.registerUpdate("DailyFX updater", "Processing state current signal", "signal processed: " + signal); } DailyLoopInfo.registerUpdate("DailyFX updater last read objects", "Last read", readLog); DailyLoopInfo.closeLoop("DailyFX updater last read objects"); for(StrategyId strategyId : strategies) { Strategy current = strategyId.strategy(); DailyLoopInfo.registerUpdate("DailyFX updater", "Processing state", "processing strategy, checking stops: " + strategyId); List <StrategySignal> signalsList = current.duplicateSignals(); for(StrategySignal signal : signalsList) { DailyLoopInfo.registerUpdate("DailyFX updater", "Processing state existing signals", "processing existing signal: " + signal); boolean found = false; for(StrategySignal newSignal : readSignals) if(current.getId().equals(newSignal.getStrategyId()) && signal.getPair().equals(newSignal.getPair())) { found = true; break; } if(!found) { lastChangeTime.set(System.currentTimeMillis()); if(current.getId() != StrategyId.BREAKOUT1) { DailyLog.addRangeInfo("cambios", "No encontrada: " + signal); } current.processSignalChange(signal.getPair(), true, signal.isBuy(), signal.getLotNumber(), 0, signal); changed = true; } } } } catch(Exception e) { if((errorCount.incrementAndGet() % 300) == 0) { DailyLog.logError(e.toString() + ": Error al procesar senales de dailyFX."); String ste = ""; for(StackTraceElement element : e.getStackTrace()) ste += element.toString() + "\n"; DailyLog.logError(ste); } } } private static final AtomicLong persistenceCounter = new AtomicLong(0); public void waitForChange() { long startTime = System.currentTimeMillis(); boolean didChange = false; systemLock.lock(); try { while(!changed && (System.currentTimeMillis() - startTime) < 100000) try { systemChanged.await(120000, TimeUnit.MILLISECONDS); } catch(InterruptedException e) { DailyLog.logError("Error de interrupcion en sistema dailyFx"); } didChange = changed; changed = false; } finally { systemLock.unlock(); } DailyLoopInfo.registerUpdate("DailyFX persistence", "State", "storing in db"); if(didChange || ((persistenceCounter.incrementAndGet() % 12) == 0)) writePersistence(); DailyLoopInfo.registerUpdate("DailyFX persistence", "State", "stored to db without errors"); } @Override public void writePersistence() { checkConsistency(); for(StrategyId e : strategies) e.strategy().writePersistency(); } }