package dailyBot.model;
import java.beans.XMLDecoder;
import java.io.File;
import java.io.FileInputStream;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import dailyBot.analysis.SignalHistoryRecord;
import dailyBot.control.DailyBotMain;
import dailyBot.control.DailyExecutor;
import dailyBot.control.DailyLog;
import dailyBot.control.DailyLoopInfo;
import dailyBot.control.DailyProperties;
import dailyBot.control.DailyRunnable;
import dailyBot.control.connection.zulutrade.ZulutradeConnection;
import dailyBot.model.Strategy.StrategyId;
public class SignalProvider
{
private interface BrokerFactory
{
public Broker[] getBrokers(SignalProviderId id);
}
public enum SignalProviderId
{
DEMO(new BrokerFactory()
{
@Override
public Broker[] getBrokers(SignalProviderId id)
{
return new Broker[] { new ZulutradeConnection(id) };
}
}, true), DAILYBOTSSIEURO(new BrokerFactory()
{
@Override
public Broker[] getBrokers(SignalProviderId id)
{
return new Broker[] { new ZulutradeConnection(id) };
}
}, false);
volatile transient SignalProvider thisSignalProvider = null;
volatile transient BrokerFactory brokerFactory;
volatile transient boolean inTesting;
private SignalProviderId(BrokerFactory broker, boolean testing)
{
brokerFactory = broker;
this.inTesting = testing;
}
public synchronized SignalProvider signalProvider()
{
if(thisSignalProvider == null)
DailyLog.logError("Proveedor " + this + " fue llamado antes de ser registrado.");
return thisSignalProvider;
}
public synchronized void startSignalProvider()
{
if(DailyProperties.isTesting() == inTesting)
{
thisSignalProvider = new SignalProvider(this);
thisSignalProvider.brokers = brokerFactory.getBrokers(this);
}
else
thisSignalProvider = new InactiveSignalProvider();
}
}
protected volatile SignalProviderId id;
protected final AtomicReference <MultiFilter> filter = new AtomicReference <MultiFilter> ();
protected volatile Broker[] brokers;
public SignalProvider()
{
}
public SignalProvider(SignalProviderId id)
{
this.id = id;
loadFilter();
}
public String checkAllBrokers()
{
String answer = "";
for(Broker broker : brokers)
answer += "\n\n" + broker.checkConsistencyFull(false);
return answer;
}
public void startPersistenceThread()
{
DailyRunnable persistenceRunnable = new DailyRunnable("Presistence " + id, 2000000L, true)
{
AtomicBoolean messageSent = new AtomicBoolean(false);
AtomicBoolean checked = new AtomicBoolean(false);
public void runOnce()
{
if(id.signalProvider() == null || checkConsistency())
{
DailyLog.logError("Error de consistencia en " + id);
id.startSignalProvider();
throw new RuntimeException("Consistency error");
}
DailyLoopInfo.registerLoop(id.toString() + " persistence");
DailyLoopInfo.registerUpdate(id.toString() + " persistence", "State", "loading filter");
try
{
loadFilter();
DailyLoopInfo.registerUpdate(id.toString() + " persistence", "State",
"filter loaded without errors");
}
catch(Exception e)
{
DailyLoopInfo.registerUpdate(id.toString() + " persistence", "State", "error loading filter "
+ e + " " + e.getMessage());
}
finally
{
DailyLoopInfo.closeLoop(id.toString() + " persistence");
}
DailyLoopInfo.registerLoop(id.toString() + " checker");
DailyLoopInfo.registerUpdate(id.toString() + " checker", "State", "checking brokers consistency");
try
{
if(!DailyBotMain.marketClosed())
checkBrokerConsistency();
}
catch(Exception e)
{
DailyLog.logError("Error chequeando consistencia del proveedor " + id);
}
finally
{
DailyLoopInfo.registerUpdate(id.toString() + " checker", "State",
"brokers consistency checked");
}
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
if(minute > 40)
{
messageSent.set(false);
checked.set(false);
}
else
{
try
{
if((!messageSent.get()) && hour == 17)
{
DailyLoopInfo.registerLoop(id.toString() + " check");
DailyLoopInfo.registerUpdate(id.toString() + " check", "State", "checking brokers");
if(!DailyBotMain.marketClosed())
for(Broker broker : brokers)
broker.checkConsistencyFull(true);
Utils.checkSignals((StrategyId) null, 0);
Utils.makeCheck(SignalProvider.this);
DailyLoopInfo.registerUpdate(id.toString() + " check", "State", "brokers checked");
DailyLoopInfo.closeLoop(id.toString() + " check");
messageSent.set(true);
checked.set(true);
}
if(!checked.get())
{
DailyLoopInfo.registerLoop(id.toString() + " check");
DailyLoopInfo.registerUpdate(id.toString() + " check", "State", "checking brokers");
if(!DailyBotMain.marketClosed())
for(Broker broker : brokers)
broker.checkConsistencyFull(false);
DailyLoopInfo.registerUpdate(id.toString() + " check", "State", "brokers checked");
DailyLoopInfo.closeLoop(id.toString() + " check");
checked.set(true);
}
}
catch(RuntimeException e)
{
DailyLoopInfo.registerUpdate(id.toString() + " checker", "State",
"error checking brokers " + e + " " + e.getMessage());
}
finally
{
DailyLoopInfo
.registerUpdate(id.toString() + " checker", "Hourly check", "check finished");
DailyLoopInfo.closeLoop(id.toString() + " checker");
}
}
}
};
DailyExecutor.addRunnable(persistenceRunnable, 5, TimeUnit.MINUTES, 3, TimeUnit.MINUTES);
}
public boolean isActive(StrategyId strategyId, Pair pair, boolean isBuy)
{
return filter.get().hasActive(strategyId, pair, isBuy);
}
public boolean filterAllow(SignalHistoryRecord record, double entryPrice)
{
if(!isActive(record.id, record.pair, record.buy))
return false;
return filter.get().filter(record, true, entryPrice);
}
public void processSignal(StrategySignal signal, boolean hit)
{
if(hit)
{
if(signal.getUniqueId(id.toString()) == 0L)
DailyLog.logError("Senal con par: " + signal.getPair() + ", estrategia: " + signal.getStrategyId()
+ ", proveedor " + id + " no existe y se intento cerrar.");
else
{
for(Broker broker : brokers)
if(broker.getUniqueId(signal) != 0)
broker.closeSignal(signal, signal.getStrategyId(), signal.getPair(), signal.isBuy());
signal.setUniqueId(id.toString(), 0L);
}
}
else
{
if(signal.getUniqueId(id.toString()) != 0L)
DailyLog.logError("Senal con par: " + signal.getPair() + ", estrategia: " + signal.getStrategyId()
+ ", proveedor " + id + " ya existe y se intento abrir otra vez.");
else
{
if(!filterAllow(new SignalHistoryRecord(signal.getStrategyId(), signal.getPair(), signal.isBuy(),
signal.getStartDate()), signal.getEntryPrice()))
for(Broker broker : brokers)
broker.setUniqueId(signal, 0L);
else
{
if(Math.abs(signal.getPair().differenceInPips(signal.getEntryPrice(), signal.isBuy())) >= 50)
{
DailyLog.logError("Senal " + signal + " se abrio demasiado tarde, diferencia absoluta en"
+ " pips: " + Math.abs(signal.getPair().differenceInPips(signal.getEntryPrice(), signal.isBuy())));
for(Broker broker : brokers)
broker.setUniqueId(signal, 0L);
}
else
for(Broker broker : brokers)
broker.openSignal(signal, signal.getStrategyId(), signal.getPair(), signal.isBuy());
}
signal.setUniqueId(id.toString(), 1);
}
}
}
//
// public void openActive(StrategyId strategyId, Pair pair)
// {
// if(!isActive(strategyId, pair))
// return;
// StrategySignal toOpen = strategyId.strategy().hasPair(pair);
// if((toOpen.getUniqueId(id.toString()) == 0L) || (toOpen == null) || (toOpen.getUniqueId(id.toString()) == 0L))
// DailyLog.logError("Senal con par: " + pair + ", estrategia: " + strategyId + ", proveedor " + id
// + " no estaba abierta y se intento reabrir.");
// else
// {
// DailyLog.logInfoWithTitle("rangos", id + " abriendo senal por orden manual: " + strategyId + ", " + pair);
// for(Broker broker : brokers)
// if(broker.getUniqueId(toOpen) == 0L)
// broker.openSignal(toOpen, toOpen.getStrategyId(), toOpen.getPair(), toOpen.isBuy());
// }
// }
public boolean checkConsistency()
{
return filter == null || id == null || brokers == null;
}
// public boolean getActive(StrategyId strategyId, Pair pair)
// {
// return isActive(strategyId, pair);
// }
public boolean closeSignal(StrategyId strategyId, Pair pair)
{
StrategySignal toClose = strategyId.strategy().hasPair(pair);
if(toClose.getUniqueId(strategyId.toString()) != 0L)
{
DailyLog.addRangeInfo("manuales", strategyId + " cerrando senal por orden manual: " + strategyId + ", "
+ pair);
boolean any = false;
for(Broker broker : brokers)
if(broker.getUniqueId(toClose) != 0L)
{
broker.closeSignal(toClose, toClose.getStrategyId(), toClose.getPair(), toClose.isBuy());
any = true;
}
if(!any)
DailyLog.logError("Error cerrando, senal no tenia id de ningun broker "
+ toClose.getUniqueIdsMap().toString());
return any;
}
else
{
DailyLog.logError("Error cerrando, senal no tenia id de proveedor " + toClose.getUniqueIdsMap().toString());
return false;
}
}
public boolean openManualSignal(Pair pair, boolean buy)
{
boolean any = false;
for(Broker broker : brokers)
if(broker.openManualSignal(pair, buy))
any = true;
return any;
}
public boolean closeManualSignal(long id)
{
boolean any = false;
for(Broker broker : brokers)
if(broker.closeManualSignal(id))
any = true;
return any;
}
public void setActive(StrategyId strategyId, Pair pair, boolean isBuy, boolean newActive)
{
boolean currentActive = isActive(strategyId, pair, isBuy);
StrategySignal signal = strategyId.strategy().hasPair(pair);
if(currentActive && !newActive)
{
if(signal != null && signal.getUniqueId(strategyId.toString()) != 0)
{
for(Broker broker : brokers)
if(broker.getUniqueId(signal) != 0)
{
broker.closeSignal(signal, signal.getStrategyId(), signal.getPair(), signal.isBuy());
DailyLog.logError("Proveedor " + this.id + ", estrategia: " + strategyId + ", par: " + pair
+ " estaba abierta y se desactivo, cerrada manualmente.");
}
signal.setUniqueId(strategyId.toString(), 0L);
}
}
else if(currentActive && newActive)
{
StrategySignal signal2 = strategyId.strategy().hasPair(pair);
if(signal2 != null && signal.getUniqueId(strategyId.toString()) == 0)
signal.setUniqueId(strategyId.toString(), 1L);
}
filter.get().changeActive(strategyId, pair, isBuy, newActive);
}
public boolean isOpen(StrategyId strategyId, Pair pair)
{
StrategySignal signal = strategyId.strategy().hasPair(pair);
return signal != null && signal.getUniqueId(id.toString()) != 0;
}
public int getProfit()
{
int profit = 0;
for(StrategySignal signal : Utils.getAllSignals())
{
boolean opened = false;
for(Broker b : brokers)
if(b.getUniqueId(signal) != 0)
opened = true;
if(opened)
profit += signal.getPair().differenceInPips(signal.getEntryPrice(), signal.isBuy());
}
return profit;
}
public void loadFilter()
{
try
{
if(!new File("filters/" + id + ".xml").exists())
{
filter.set(new MultiFilter(id));
filter.get().startFilters();
}
else
{
FileInputStream fis = new FileInputStream("filters/" + id + ".xml");
XMLDecoder decoder = new XMLDecoder(fis);
MultiFilter answer = (MultiFilter) decoder.readObject();
fis.close();
decoder.close();
filter.set(answer);
filter.get().startFilters();
}
}
catch(Exception e)
{
DailyLog.logError("Error reading filter: " + id.name());
filter.set(new MultiFilter(id));
filter.get().startFilters();
}
}
public MultiFilter getFilter()
{
return filter.get();
}
public List <StrategySignal> providerSignals()
{
LinkedList <StrategySignal> all = new LinkedList <StrategySignal>();
for(StrategySignal signal : Utils.getAllSignals())
if(signal.getUniqueId(id.toString()) != 0)
all.add(signal);
return all;
}
public SignalProviderId getId()
{
return id;
}
public void setId(SignalProviderId id)
{
this.id = id;
}
public boolean filterActive()
{
return filter.get().isActive();
}
public void changeFilterActive(boolean newActive)
{
filter.get().setActive(newActive);
}
public void checkBrokerConsistency()
{
for(Broker broker : brokers)
broker.checkConsistency();
}
public void changeActiveFilter(StrategyId strategyId, Pair pair, boolean isBuy,
int newValue)
{
filter.get().changeActiveFilter(strategyId, pair, isBuy, newValue);
}
public String checkFilterActive()
{
if(!filter.get().isActive())
return "Unactive filter";
String answer = "";
for(StrategyId strategy : StrategyId.values())
{
boolean putStrategy = false;
for(Pair pair : Pair.values())
{
for(boolean buy : new boolean[]{true, false})
if(filter.get().hasActive(strategy, pair, buy))
{
int i = filter.get().getActiveFilters()[strategy.ordinal()][pair.ordinal()][buy ? 1 : 0];
if(i <= 1)
continue;
if(!putStrategy)
answer += "\n" + strategy + ":\n";
putStrategy = true;
answer += pair + " " + buy;
boolean or = (i & 1) == 1;
i >>= 1;
Filter[] filters = filter.get().filters();
for(int j = 0; j < filters.length; j++)
{
if((i & 1) == 1)
answer += " " + filters[j].getName();
i >>= 1;
}
if(!or)
answer += " and";
answer += "\n";
}
}
}
answer = answer.trim();
if(answer.isEmpty())
answer += "No active pairs";
return answer;
}
}