From 7172466764a3105f8d3eab69956eac2b6abe2151 Mon Sep 17 00:00:00 2001 From: elroy Date: Sat, 22 Jul 2017 14:52:44 +0200 Subject: [PATCH] remove clutter, this code has been branched --- .gitignore | 1 + .../bot/EnhancedCrossedDownIndicatorRule.java | 32 -- .../komtek/gpi/bot/IndicatorCalculators.java | 393 ------------------ .../java/nl/komtek/gpi/bot/NamedStrategy.java | 71 ---- .../gpi/bot/RiskRewardRatioCriterion.java | 37 -- 5 files changed, 1 insertion(+), 533 deletions(-) delete mode 100644 src/main/java/nl/komtek/gpi/bot/EnhancedCrossedDownIndicatorRule.java delete mode 100644 src/main/java/nl/komtek/gpi/bot/IndicatorCalculators.java delete mode 100644 src/main/java/nl/komtek/gpi/bot/NamedStrategy.java delete mode 100644 src/main/java/nl/komtek/gpi/bot/RiskRewardRatioCriterion.java diff --git a/.gitignore b/.gitignore index c7ae386..383080b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target .idea application.properties +logs diff --git a/src/main/java/nl/komtek/gpi/bot/EnhancedCrossedDownIndicatorRule.java b/src/main/java/nl/komtek/gpi/bot/EnhancedCrossedDownIndicatorRule.java deleted file mode 100644 index c52264f..0000000 --- a/src/main/java/nl/komtek/gpi/bot/EnhancedCrossedDownIndicatorRule.java +++ /dev/null @@ -1,32 +0,0 @@ -package nl.komtek.gpi.bot; - -import eu.verdelhan.ta4j.Decimal; -import eu.verdelhan.ta4j.Indicator; -import eu.verdelhan.ta4j.TradingRecord; -import eu.verdelhan.ta4j.trading.rules.CrossedDownIndicatorRule; - -/** - * Created by Elroy on 27-6-2017. - */ -public class EnhancedCrossedDownIndicatorRule extends CrossedDownIndicatorRule { - - private Integer overrideIndex; - public EnhancedCrossedDownIndicatorRule(Indicator indicator, Decimal threshold, Integer overrideIndex) { - super(indicator, threshold); - this.overrideIndex = overrideIndex; - } - - public EnhancedCrossedDownIndicatorRule(Indicator first, Indicator second, Integer overrideIndex) { - super(first, second); - this.overrideIndex = overrideIndex; - } - - @Override - public boolean isSatisfied(int index, TradingRecord tradingRecord) { - int newIndex = index; - if (overrideIndex != null){ - newIndex = index / overrideIndex; - } - return super.isSatisfied(newIndex, tradingRecord); - } -} diff --git a/src/main/java/nl/komtek/gpi/bot/IndicatorCalculators.java b/src/main/java/nl/komtek/gpi/bot/IndicatorCalculators.java deleted file mode 100644 index cb82fe8..0000000 --- a/src/main/java/nl/komtek/gpi/bot/IndicatorCalculators.java +++ /dev/null @@ -1,393 +0,0 @@ -package nl.komtek.gpi.bot; - -import com.cf.client.poloniex.PoloniexExchangeService; -import com.cf.data.map.poloniex.PoloniexDataMapper; -import com.cf.data.model.poloniex.PoloniexChartData; -import eu.verdelhan.ta4j.AnalysisCriterion; -import eu.verdelhan.ta4j.Decimal; -import eu.verdelhan.ta4j.Indicator; -import eu.verdelhan.ta4j.Rule; -import eu.verdelhan.ta4j.Strategy; -import eu.verdelhan.ta4j.Tick; -import eu.verdelhan.ta4j.TimeSeries; -import eu.verdelhan.ta4j.Trade; -import eu.verdelhan.ta4j.TradingRecord; -import eu.verdelhan.ta4j.analysis.criteria.AverageProfitableTradesCriterion; -import eu.verdelhan.ta4j.analysis.criteria.TotalProfitCriterion; -import eu.verdelhan.ta4j.indicators.simple.ClosePriceIndicator; -import eu.verdelhan.ta4j.indicators.statistics.StandardDeviationIndicator; -import eu.verdelhan.ta4j.indicators.trackers.SMAIndicator; -import eu.verdelhan.ta4j.indicators.trackers.bollinger.BollingerBandsLowerIndicator; -import eu.verdelhan.ta4j.indicators.trackers.bollinger.BollingerBandsMiddleIndicator; -import eu.verdelhan.ta4j.trading.rules.StopGainRule; -import eu.verdelhan.ta4j.trading.rules.StopLossRule; -import nl.komtek.gpi.services.GunbotProxyService; -import org.joda.time.DateTime; - -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * Created by Elroy on 26-6-2017. - */ -public class IndicatorCalculators { - - private static boolean analysisMode = false; - private static String testCurrency = null; - private static double profitRatio = 0.60; - private static boolean analysisModeProfitOnly = false; - private GunbotProxyService GunbotProxyService = new GunbotProxyService(); - private final PoloniexDataMapper mapper = new PoloniexDataMapper(); - private static final PoloniexExchangeService poloniexExchangeService = new PoloniexExchangeService("", ""); - private static NumberFormat formatter = new DecimalFormat("0.000000000"); - - private AnalysisCriterion profitTradesRatio = new AverageProfitableTradesCriterion(); - private TotalProfitCriterion profitCriterion = new TotalProfitCriterion(); - private AnalysisCriterion riskRewardRatio = new RiskRewardRatioCriterion(); - - private Map> marketDataMap = new ConcurrentHashMap<>(); - - public Optional calculateBestStrategy(String currency, int startSampleDays, int totalSampleDays, - boolean onlyShowBest) { - - Calendar start = Calendar.getInstance(); - start.add(Calendar.DATE, startSampleDays); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - Calendar end = Calendar.getInstance(); - end.add(Calendar.DATE, startSampleDays + totalSampleDays); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - - TimeSeries fiveMinuteSeries = createTimeSeries(currency, start.getTimeInMillis(), end.getTimeInMillis(), 300); - TimeSeries thirthyMinuteSeries = createTimeSeries(currency, start.getTimeInMillis(), end.getTimeInMillis(), 1800); - - //5 minutes - ClosePriceIndicator fiveMinuteClose = new ClosePriceIndicator(fiveMinuteSeries); - BollingerBandsLowerIndicator fiveMinuteBBLow = createBBLow(fiveMinuteSeries, fiveMinuteClose, 50); - - //30 minutes - ClosePriceIndicator thirthyMinuteClose = new ClosePriceIndicator(thirthyMinuteSeries); - BollingerBandsLowerIndicator thirthyMinuteBBLow = createBBLow(thirthyMinuteSeries, thirthyMinuteClose, 50); - - Rule buyingRule = new EnhancedCrossedDownIndicatorRule(fiveMinuteBBLow, fiveMinuteClose, 1) - .and(new EnhancedCrossedDownIndicatorRule(thirthyMinuteBBLow, thirthyMinuteClose, 6)); - - Map strategyAndResult = new HashMap<>(); - for (int gain = 2; gain <= 10; gain++) { - for (int loss = 1; loss <= 10; loss++) { - if (loss > gain) { - continue; - } - Rule sellingRule = new StopGainRule(fiveMinuteClose, Decimal.valueOf(gain)) - .or(new StopLossRule(fiveMinuteClose, Decimal.valueOf(loss))); - NamedStrategy strategy = new NamedStrategy(currency, gain, loss, buyingRule, sellingRule); - TradingRecord tradingRecord = fiveMinuteSeries.run(strategy); - if (!isValidStrategy(fiveMinuteSeries, tradingRecord)) { - continue; - } - strategyAndResult.put(strategy, tradingRecord); - } - } - - NamedStrategy strategy = null; - if (strategyAndResult.size() > 0) { - if (analysisMode) { - printStrategyStatistics(fiveMinuteSeries, strategyAndResult, onlyShowBest); - } - strategy = (NamedStrategy) profitCriterion.chooseBest(fiveMinuteSeries, new ArrayList<>(strategyAndResult.keySet())); - } - return Optional.ofNullable(strategy); - } - - public double runStrategy(NamedStrategy strategy, String currency, - long startInMillis, long endInMillis) throws Exception { - - TimeSeries fiveMinuteSeries = createTimeSeries(currency, startInMillis, endInMillis, 300); - TimeSeries thirthyMinuteSeries = createTimeSeries(currency, startInMillis, endInMillis, 1800); - - //5 minutes - ClosePriceIndicator fiveMinuteClose = new ClosePriceIndicator(fiveMinuteSeries); - BollingerBandsLowerIndicator fiveMinuteBBLow = createBBLow(fiveMinuteSeries, fiveMinuteClose, 40); - - //30 minutes - ClosePriceIndicator thirthyMinuteClose = new ClosePriceIndicator(thirthyMinuteSeries); - BollingerBandsLowerIndicator thirthyMinuteBBLow = createBBLow(thirthyMinuteSeries, thirthyMinuteClose, 40); - - Rule buyingRule = new EnhancedCrossedDownIndicatorRule(fiveMinuteBBLow, fiveMinuteClose, 1) - .and(new EnhancedCrossedDownIndicatorRule(thirthyMinuteBBLow, thirthyMinuteClose, 6)); - - int gain = strategy.getGain(); - int loss = strategy.getLoss(); - - Rule sellingRule = new StopGainRule(fiveMinuteClose, Decimal.valueOf(gain)) - .or(new StopLossRule(fiveMinuteClose, Decimal.valueOf(loss))); - NamedStrategy runStrategy = new NamedStrategy(currency, gain, loss, buyingRule, sellingRule); - - Map strategyAndResult = new HashMap<>(); - TradingRecord tradingRecord = fiveMinuteSeries.run(runStrategy); - - if (tradingRecord.getTradeCount() == 0) { - return 0; - } - - DateTime date = new DateTime(startInMillis); - System.out.println(date + "--" + currency + "-" + tradingRecord.getTradeCount()); - strategyAndResult.put(runStrategy, tradingRecord); - if (1 == 2) { - System.out.println("Running the strategy for " + currency + "......"); - double profit = printStrategyStatistics(fiveMinuteSeries, strategyAndResult, false); - System.out.println("End run"); - } - double profit = profitCriterion.calculate(fiveMinuteSeries, tradingRecord); - - return profit; - } - - private TimeSeries createTimeSeries(String currency, long startInMillis, long endInMillis, long period) { - - List xMinuteChartData = marketDataMap.get(currency + "_" + period); - List ticks = new ArrayList<>(); - for (PoloniexChartData data : xMinuteChartData) { - - if ((data.date * 1000) >= startInMillis && (data.date * 1000) < endInMillis) { - Tick tick = new Tick( - new DateTime(data.date * 1000), data.open, data.high, - data.low, data.close, data.volume.doubleValue()); - - ticks.add(tick); - } - } - return new TimeSeries(ticks); - } - - private boolean isValidStrategy(TimeSeries series, TradingRecord tradingRecord) { - if (tradingRecord.getTradeCount() == 0) { - return false; - } - - if (profitTradesRatio.calculate(series, tradingRecord) < profitRatio) { - return false; - } - return true; - } - - public void collectMarketData(List markets, List periods) { - Calendar start = Calendar.getInstance(); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - start.add(Calendar.DATE, -165); - Calendar end = Calendar.getInstance(); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - System.out.println("Starting data collection " + end.toString()); - ExecutorService es = Executors.newCachedThreadPool(); - for (String market : markets) { - if (!market.startsWith("USDT_")) { - continue; - } - if (testCurrency != null && !market.equals(testCurrency)) { - continue; - } - es.execute(() -> { - for (Long period : periods) { - String xMinuteChartDataRaw = GunbotProxyService.getBBChartData(market, - start.getTimeInMillis() / 1000, end.getTimeInMillis() / 1000, period); - List xMinuteChartData = mapper.mapChartData(xMinuteChartDataRaw); - marketDataMap.put(market + "_" + period, xMinuteChartData); - } - }); - - } - es.shutdown(); - try { - boolean finshed = es.awaitTermination(5, TimeUnit.MINUTES); - System.out.println("Data collection ended " + Calendar.getInstance().toString()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - - private double printStrategyStatistics(TimeSeries series, - Map strategyAndResultMap, - boolean onlyShowBest) { - double profit = 0; - - Strategy bestProfitableTradeStrategy = profitTradesRatio.chooseBest(series, new ArrayList<>(strategyAndResultMap.keySet())); - Strategy bestProfitStrategy = profitCriterion.chooseBest(series, new ArrayList<>(strategyAndResultMap.keySet())); - - for (Map.Entry entry : strategyAndResultMap.entrySet()) { - NamedStrategy strategy = entry.getKey(); - TradingRecord tradingRecord = entry.getValue(); - - if (onlyShowBest && (!strategy.equals(bestProfitableTradeStrategy) && !strategy.equals(bestProfitStrategy))) { - continue; - } - - System.out.println(String.format("-------------------%s------------------------", strategy)); - if (onlyShowBest) { - if (strategy.equals(bestProfitableTradeStrategy)) { - System.out.println("Best Profitable -- Number of trades for our strategy: " + tradingRecord.getTradeCount()); - } else { - System.out.println("Best Profit -- Number of trades for our strategy: " + tradingRecord.getTradeCount()); - } - } else { - System.out.println("Number of trades for our strategy: " + tradingRecord.getTradeCount()); - } - - // Getting the profitable trades ratio - System.out.println("Profitable trades ratio: " + profitTradesRatio.calculate(series, tradingRecord)); - System.out.println("Risk-reward ratio: " + riskRewardRatio.calculate(series, tradingRecord)); - for (Trade trade : tradingRecord.getTrades()) { - Tick tick = series.getTick(trade.getEntry().getIndex()); - String endTime = tick.getEndTime().toString("hh:mm dd/MM/yyyy"); - String openValue = formatter.format(tick.getOpenPrice().toDouble()); - System.out.println(String.format("Date:%s, Open:%s", endTime, openValue)); - } - double tmpProfit = profitCriterion.calculate(series, tradingRecord); - System.out.println("Profit:" + tmpProfit); - profit += tmpProfit; - } - //profit = profit / strategyAndResultMap.size(); - //System.out.println("Total Profit: " + profit); - System.out.println(""); - System.out.println(String.format("---------------------------------------------------------")); - - return profit; - } - - private BollingerBandsLowerIndicator createBBLow(TimeSeries series, ClosePriceIndicator close, int timeFrame) { - Indicator SMA = new SMAIndicator(close, timeFrame); - StandardDeviationIndicator SD = new StandardDeviationIndicator(new ClosePriceIndicator(series), timeFrame); - BollingerBandsMiddleIndicator bb_mid = new BollingerBandsMiddleIndicator(SMA); - BollingerBandsLowerIndicator bb_low = new BollingerBandsLowerIndicator(bb_mid, SD, Decimal.valueOf(2)); - - return bb_low; - } - - public static void main(String[] args) { - analysisMode = false; - //testCurrency = "BTC_BTS"; - profitRatio = 0.0; - int totalSampleDays = 7; - int startSampleDays = -(totalSampleDays + 1); - IndicatorCalculators calculators = new IndicatorCalculators(); - List markets = poloniexExchangeService.returnAllMarkets(); - List periods = new ArrayList<>(); - List profits = new ArrayList<>(); - periods.add(300L); - periods.add(1800L); - ExecutorService es; - List> tasks = new ArrayList<>(); - calculators.collectMarketData(markets, periods); - - for (int sampleDays = 7; sampleDays <= totalSampleDays; sampleDays++) { - profits.clear(); - for (int tradingDay = 0; tradingDay < 15; tradingDay++) { - - Calendar start = Calendar.getInstance(); - start.add(Calendar.DATE, startSampleDays + sampleDays - tradingDay); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - Calendar end = Calendar.getInstance(); - end.add(Calendar.DATE, startSampleDays + sampleDays - tradingDay + 1); - start.set(Calendar.HOUR,0); - start.set(Calendar.MINUTE,0); - start.set(Calendar.SECOND,0); - start.set(Calendar.MILLISECOND,0); - //System.out.println(String.format("%d-%d-%d", start.get(Calendar.DATE), start.get(Calendar.MONTH) + 1, start.get(Calendar.YEAR))); - es = Executors.newCachedThreadPool(); - tasks.clear(); - for (String market : markets) { - if (!market.startsWith("USDT_")) { - continue; - } - if (testCurrency != null && !market.equals(testCurrency)) { - continue; - } - int currentTradingDay = tradingDay; - int currentSampledays = sampleDays; - - Future future = es.submit(() -> { - Optional bestStrategy = calculators.calculateBestStrategy(market, startSampleDays - currentTradingDay, currentSampledays, true); - - if (bestStrategy.isPresent()) { - double tmpProfit = 0; - try { - tmpProfit = calculators.runStrategy(bestStrategy.get(), market, start.getTimeInMillis(), end.getTimeInMillis()); - } catch (Exception e) { - System.out.println(String.format("Currency %s threw an exception for tradingDay: %d and sampleDay:%d", - market, currentTradingDay, currentSampledays)); - } - - synchronized (profits) { - if (tmpProfit > 0) { - profits.add(tmpProfit); - } - } - } - }); - tasks.add(() -> future); - } - try { - - es.invokeAll(tasks); - - es.shutdown(); - while(!es.isTerminated()){ - - } - OptionalDouble avg = profits.stream().mapToDouble(d -> d).average(); - //System.out.println(String.format("Daily:%d -- Average profit:%f on total trades %f", sampleDays, avg.orElse(0.0), profits.size())); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - } - OptionalDouble avg = profits.stream().mapToDouble(d -> d).average(); - System.out.println(String.format("2 weeks:%d -- Average profit:%f on total trades %d", sampleDays, avg.orElse(0.0), profits.size())); - } - } - -// // rising markets -// if(percentChange > 0.015) { -// baseBuyLevel = baseBuyLevel / 2; -// baseBuyLevelIncreasePerVolume = baseBuyLevelIncreasePerVolume / 2; -// } -// -// // fallings markets -// else if(percentChange < -0.015) { -// baseBuyLevel = baseBuyLevel / 1; -// baseBuyLevelIncreasePerVolume = baseBuyLevelIncreasePerVolume / 1; -// } -// -// // steady markets -// else { -// baseBuyLevel = baseBuyLevel / 1.5; -// baseBuyLevelIncreasePerVolume = baseBuyLevelIncreasePerVolume / 1.5; -// } -} diff --git a/src/main/java/nl/komtek/gpi/bot/NamedStrategy.java b/src/main/java/nl/komtek/gpi/bot/NamedStrategy.java deleted file mode 100644 index 09d7052..0000000 --- a/src/main/java/nl/komtek/gpi/bot/NamedStrategy.java +++ /dev/null @@ -1,71 +0,0 @@ -package nl.komtek.gpi.bot; - -import eu.verdelhan.ta4j.Rule; -import eu.verdelhan.ta4j.Strategy; - -/** - * Created by Elroy on 28-6-2017. - */ -public class NamedStrategy extends Strategy { - - private String name; - private int gain; - private int loss; - - public NamedStrategy(String name, int gain, int loss, Rule entryRule, Rule exitRule) { - super(entryRule, exitRule); - this.name = name; - this.gain = gain; - this.loss = loss; - } - - public String getName() { - return name; - } - - public int getGain() { - return gain; - } - - public int getLoss() { - return loss; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("NamedStrategy{"); - sb.append("name='").append(name).append('\''); - sb.append(", gain=").append(gain); - sb.append(", loss=").append(loss); - sb.append('}'); - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - NamedStrategy strategy = (NamedStrategy) o; - - if (gain != strategy.gain) { - return false; - } - if (loss != strategy.loss) { - return false; - } - return name.equals(strategy.name); - } - - @Override - public int hashCode() { - int result = name.hashCode(); - result = 31 * result + gain; - result = 31 * result + loss; - return result; - } -} diff --git a/src/main/java/nl/komtek/gpi/bot/RiskRewardRatioCriterion.java b/src/main/java/nl/komtek/gpi/bot/RiskRewardRatioCriterion.java deleted file mode 100644 index 982c7e3..0000000 --- a/src/main/java/nl/komtek/gpi/bot/RiskRewardRatioCriterion.java +++ /dev/null @@ -1,37 +0,0 @@ -package nl.komtek.gpi.bot; - -import eu.verdelhan.ta4j.AnalysisCriterion; -import eu.verdelhan.ta4j.TimeSeries; -import eu.verdelhan.ta4j.Trade; -import eu.verdelhan.ta4j.TradingRecord; -import eu.verdelhan.ta4j.analysis.criteria.AbstractAnalysisCriterion; -import eu.verdelhan.ta4j.analysis.criteria.MaximumDrawdownCriterion; -import eu.verdelhan.ta4j.analysis.criteria.TotalProfitCriterion; - -/** - * Risk reward ratio criterion. - *

- * (i.e. {@link MaximumDrawdownCriterion maximum drawdown} the over the {@link TotalProfitCriterion total profit}. - */ -public class RiskRewardRatioCriterion extends AbstractAnalysisCriterion { - - private AnalysisCriterion totalProfit = new TotalProfitCriterion(); - - private AnalysisCriterion maxDrawdown = new MaximumDrawdownCriterion(); - - @Override - public double calculate(TimeSeries series, TradingRecord tradingRecord) { - return maxDrawdown.calculate(series, tradingRecord) / totalProfit.calculate(series, tradingRecord); - } - - @Override - public boolean betterThan(double criterionValue1, double criterionValue2) { - return criterionValue1 < criterionValue2; - } - - @Override - public double calculate(TimeSeries series, Trade trade) { - return maxDrawdown.calculate(series, trade) / totalProfit.calculate(series, trade); - } - -}