|
@@ -0,0 +1,237 @@
|
|
|
|
|
+package controllers.strategytest;
|
|
|
|
|
+
|
|
|
|
|
+import components.FloatStatRow;
|
|
|
|
|
+import components.IntTableStatRow;
|
|
|
|
|
+import components.NumberStatRow;
|
|
|
|
|
+import interfaces.strategytest.BettingStrategyInterface;
|
|
|
|
|
+import javafx.scene.layout.VBox;
|
|
|
|
|
+import objects.SoccerMatch;
|
|
|
|
|
+import objects.SoccerMatchAnalysis;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Arrays;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Optional;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * The basic concept of betting according to the Fibonacci sequence is simple: bet on a tie.
|
|
|
|
|
+ If you lose, just bet on the next tie according to a certain key and start increasing your stake.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * It is important that the odds for the tie are above 2.62 (more precisely: 2.618);
|
|
|
|
|
+ * luckily for those who want to employ this strategy, there are many tie bets for this minimum odds.
|
|
|
|
|
+ The higher the rate, the better.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * Fibonacci Betting Strategy
|
|
|
|
|
+ * Betting after Fibonacci
|
|
|
|
|
+ * If you lose, you simply bet the next tie after a Fibonacci sequence.
|
|
|
|
|
+ It is a sequence of numbers in which the sum of two consecutive numbers results in the next number, making the Fibonacci sequence an infinite sequence of natural numbers.
|
|
|
|
|
+ You can find more information about the Fibonacci sequence on Wikipedia.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * Fibonacci numbers
|
|
|
|
|
+ * The Fibonacci sequence
|
|
|
|
|
+ * So if you start betting with 1 € on the first draw with odds> 2.
|
|
|
|
|
+62 and lose, then the next time you bet 1 € again, then 2 €, then 3 €, then 5 €, then 8 €, then 13 € and so on.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * It is mathematically understandable that every profit that you will achieve with this bet will offset the previous losses and you will even make a net profit.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * An example of the Fibonacci bet
|
|
|
|
|
+ *
|
|
|
|
|
+ * Let’s take the example of the situation where you lose ten times in a row and win your bet the eleventh time.
|
|
|
|
|
+ In this case, you have already gambled away 143 € and finally successfully placed the eleventh number in the Fibonacci sequence, 144, on a bet.
|
|
|
|
|
+ If we now assume that the successful bet had odds of @ 2.
|
|
|
|
|
+80, you win 403.
|
|
|
|
|
+20 €.
|
|
|
|
|
+ You have wagered a total of 287 €, making your net profit 116.
|
|
|
|
|
+20 €.
|
|
|
|
|
+
|
|
|
|
|
+ *
|
|
|
|
|
+ * The disadvantage of this strategy is also obvious.
|
|
|
|
|
+ Assuming you lose not ten bets in a row, but twenty, then you would have already lost 16,910 € in stakes.
|
|
|
|
|
+ This is a huge bankroll, which you should of course never risk for such a betting sequence.
|
|
|
|
|
+ You can find more about this in our explanations on bankroll management.
|
|
|
|
|
+
|
|
|
|
|
+ */
|
|
|
|
|
+public class FibonacciStrategy extends VBox implements BettingStrategyInterface {
|
|
|
|
|
+
|
|
|
|
|
+ public static final String NAME = "Fibonacci";
|
|
|
|
|
+ List<SoccerMatch> matches;
|
|
|
|
|
+ private FloatStatRow betAmount;
|
|
|
|
|
+ private FloatStatRow wonLossBankStatRow;
|
|
|
|
|
+ private NumberStatRow sequencesPlayedStatRow;
|
|
|
|
|
+ private IntTableStatRow resultStatRow;
|
|
|
|
|
+
|
|
|
|
|
+ private final int maxActiveFibonacciSequences = 4;
|
|
|
|
|
+ private final List<FibonacciSequence> fibonacciSequences = new ArrayList<>();
|
|
|
|
|
+ private NumberStatRow sequencesWonStatRow;
|
|
|
|
|
+
|
|
|
|
|
+ public FibonacciStrategy() {
|
|
|
|
|
+ super();
|
|
|
|
|
+ buildSettingsGuiPanel();
|
|
|
|
|
+ buildStatGuiPanel();
|
|
|
|
|
+ buildMatchSummaryPanel();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void setMatches(List<SoccerMatch> matches) {
|
|
|
|
|
+ this.matches = matches;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void buildSettingsGuiPanel() {
|
|
|
|
|
+ betAmount = new FloatStatRow("Bet Amount", 10f);
|
|
|
|
|
+ this.getChildren().add(betAmount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void buildStatGuiPanel() {
|
|
|
|
|
+ sequencesPlayedStatRow = new NumberStatRow("Number of sequences played", 0);
|
|
|
|
|
+ sequencesWonStatRow = new NumberStatRow("Number of sequences won", 0);
|
|
|
|
|
+ resultStatRow = new IntTableStatRow("Longest sequence without win");
|
|
|
|
|
+
|
|
|
|
|
+ wonLossBankStatRow = new FloatStatRow("Amount won or lost", 0f);
|
|
|
|
|
+
|
|
|
|
|
+ this.getChildren().add(sequencesPlayedStatRow);
|
|
|
|
|
+ this.getChildren().add(sequencesWonStatRow);
|
|
|
|
|
+ this.getChildren().add(resultStatRow);
|
|
|
|
|
+ this.getChildren().add(wonLossBankStatRow);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void buildMatchSummaryPanel() {
|
|
|
|
|
+ // Empty for now
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void runTest() {
|
|
|
|
|
+
|
|
|
|
|
+ float lowestBankAmount = 0f;
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < matches.size(); i++) {
|
|
|
|
|
+ SoccerMatch m = matches.get(i);
|
|
|
|
|
+ List<SoccerMatch> soccerMatches = filterTodaysMatches(matches, m);
|
|
|
|
|
+
|
|
|
|
|
+ List<SoccerMatch> sortedMatchList = sortMatchesOnBetPotential(soccerMatches);
|
|
|
|
|
+
|
|
|
|
|
+ for (SoccerMatch match : sortedMatchList) {
|
|
|
|
|
+ boolean removeSequence = false;
|
|
|
|
|
+ String shouldBetOn = shouldBetOn(match);
|
|
|
|
|
+ FibonacciSequence activeSequence = null;
|
|
|
|
|
+ if (shouldBetOn.equals("X")) {
|
|
|
|
|
+ Optional<FibonacciSequence> fibSeq = fibonacciSequences.stream().filter(fs -> !fs.containsMatchFromSameDate(match)).findFirst();
|
|
|
|
|
+ if (fibSeq.isPresent()) {
|
|
|
|
|
+ // Add to current sequence
|
|
|
|
|
+ activeSequence = fibSeq.get();
|
|
|
|
|
+ if (activeSequence.bets.size() + 1 > FibonacciSequence.fibonacciSequence.size()) {
|
|
|
|
|
+ System.out.println("System FAILED " + match.getGameDate() + " lost " + activeSequence.totalBetValue + " current bank " + wonLossBankStatRow.getValue());
|
|
|
|
|
+ System.out.println("Lowest bank amount " + lowestBankAmount);
|
|
|
|
|
+ removeSequence = true;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ activeSequence.addBet(match);
|
|
|
|
|
+ wonLossBankStatRow.decreaseValue(activeSequence.currentBetValue);
|
|
|
|
|
+ if (wonLossBankStatRow.getValue() < lowestBankAmount) {
|
|
|
|
|
+ lowestBankAmount = wonLossBankStatRow.getValue();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Start new if not at max active sequences
|
|
|
|
|
+ if (fibonacciSequences.size() < maxActiveFibonacciSequences) {
|
|
|
|
|
+ activeSequence = new FibonacciSequence(match);
|
|
|
|
|
+ sequencesPlayedStatRow.increaseValue();
|
|
|
|
|
+ wonLossBankStatRow.decreaseValue(activeSequence.currentBetValue);
|
|
|
|
|
+ fibonacciSequences.add(activeSequence);
|
|
|
|
|
+ if (wonLossBankStatRow.getValue() < lowestBankAmount) {
|
|
|
|
|
+ lowestBankAmount = wonLossBankStatRow.getValue();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Should not add more sequences, break loop
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (activeSequence != null) {
|
|
|
|
|
+ if (removeSequence) {
|
|
|
|
|
+ // Sequence reached max size
|
|
|
|
|
+ fibonacciSequences.remove(activeSequence);
|
|
|
|
|
+ } else if (match.getMatchResult().equals("X")) {
|
|
|
|
|
+ // WON
|
|
|
|
|
+ resultStatRow.increaseValue(activeSequence.bets.size());
|
|
|
|
|
+ sequencesWonStatRow.increaseValue();
|
|
|
|
|
+
|
|
|
|
|
+ final float wonAmount = activeSequence.currentBetValue * match.getOddsX();
|
|
|
|
|
+ wonLossBankStatRow.increaseValue(wonAmount);
|
|
|
|
|
+ // Sequence won, remove sequence
|
|
|
|
|
+ fibonacciSequences.remove(activeSequence);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ i += sortedMatchList.size();
|
|
|
|
|
+ }
|
|
|
|
|
+ System.out.println("FibonacciStrategy.runTest() lest unresolved sequences: ");
|
|
|
|
|
+ fibonacciSequences.forEach(fs -> System.out.println("Sequence: " + fs.bets.size() + " outstanding bets value: " + fs.totalBetValue));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Matchen måste ha ett odds på X på minst 2.618
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String shouldBetOn(SoccerMatch match) {
|
|
|
|
|
+ return match.getOddsX() >= 2.618 ? "X" : "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<SoccerMatch> sortMatchesOnBetPotential(List<SoccerMatch> matches) {
|
|
|
|
|
+ //matches.sort((m1, m2) -> Float.compare(m1.getOddsX(), m2.getOddsX()));
|
|
|
|
|
+
|
|
|
|
|
+ matches.sort((m2, m1) -> Float.compare(new SoccerMatchAnalysis(m1).calculateWinPercentages().getDrawPercentage(),
|
|
|
|
|
+ new SoccerMatchAnalysis(m2).calculateWinPercentages().getDrawPercentage()));
|
|
|
|
|
+ return matches;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void reset() {
|
|
|
|
|
+ fibonacciSequences.clear();
|
|
|
|
|
+ sequencesPlayedStatRow.getChildren().clear();
|
|
|
|
|
+ sequencesWonStatRow.getChildren().clear();
|
|
|
|
|
+ resultStatRow.getChildren().clear();
|
|
|
|
|
+ wonLossBankStatRow.getChildren().clear();
|
|
|
|
|
+
|
|
|
|
|
+ buildStatGuiPanel();
|
|
|
|
|
+ buildMatchSummaryPanel();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private class FibonacciSequence {
|
|
|
|
|
+
|
|
|
|
|
+ public static final List<Integer> fibonacciSequence = Arrays.asList(1, 1, 2, 3, 5, 8, 13, 21, 34, 55); //, 89, 144, 233, 377, 610);
|
|
|
|
|
+ List<SoccerMatch> bets = new ArrayList<>();
|
|
|
|
|
+ float totalBetValue = 0f;
|
|
|
|
|
+
|
|
|
|
|
+ float currentBetValue = 0f;
|
|
|
|
|
+
|
|
|
|
|
+ FibonacciSequence(SoccerMatch match) {
|
|
|
|
|
+ bets.add(match);
|
|
|
|
|
+ totalBetValue += betAmount.getValue();
|
|
|
|
|
+ currentBetValue = betAmount.getValue();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void addBet(SoccerMatch match) {
|
|
|
|
|
+ totalBetValue += betAmount.getValue() * fibonacciSequence.get(bets.size());
|
|
|
|
|
+ currentBetValue = betAmount.getValue() * fibonacciSequence.get(bets.size());
|
|
|
|
|
+
|
|
|
|
|
+ bets.add(match);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean containsBet(SoccerMatch match) {
|
|
|
|
|
+ return bets.contains(match);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean containsMatchFromSameDate(SoccerMatch match) {
|
|
|
|
|
+ return bets.stream().anyMatch(b -> b.getGameDate().toLocalDate().isEqual(match.getGameDate().toLocalDate()));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|