Created
November 1, 2020 00:14
-
-
Save matthewdowney/6ba020b8bcd1334d4c4e6a51bc4c8530 to your computer and use it in GitHub Desktop.
The deterministic algorithm behind the casino game https://roobet.com/crash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns user.crash | |
"The deterministic algorithm behind the casino game https://roobet.com/crash. | |
Includes code to | |
- generate a crash point from a game hash | |
- generate all game hashes and crash points since the start of the game | |
- simulate betting strategies (n.b. this is just for fun, as there's no way | |
to make a bet with a positive expected value)" | |
(:require [pandect.algo.sha256 :as sha])) | |
;; hash of bitcoin block #610546 | |
;; https://twitter.com/Roobet/status/1211800855223123968 | |
(def salt "0000000000000000000fa3b65e43e4240d71762a5bf397d5304b2596d116859c") | |
(defn hex-biginteger [^String s] (BigInteger. s 16)) | |
(defn rpartition-all | |
"Like partition-all, except the first chunk -- rather than the last -- may | |
contain fewer than `n` elements if `xs` cannot be chunked evenly." | |
[n xs] | |
(map reverse (reverse (partition-all n (reverse xs))))) | |
;; To be completely honest I'm not sure why Roobet's sample code implements | |
;; modulus against hex strings instead of just parsing the hex string to a | |
;; number and using JavaScript's modulus (see sample @ https://roobet.com/fair), | |
;; but I'm going to port their code faithfully because ... chesterton's fence | |
(defn divisible? [hex modn] | |
(let [chunk->n #(hex-biginteger (apply str %))] | |
(zero? | |
(reduce | |
(fn [val n] (mod (+ (.shiftLeft (biginteger val) 16) n) modn)) | |
0 | |
(map chunk->n (rpartition-all 4 hex)))))) | |
(defn crash-point | |
"The crash point for game given its hash." | |
[game-hash] | |
(let [hash (sha/sha256-hmac salt game-hash) | |
e (Math/pow 2 52) | |
h (BigInteger. (subs hash 0 13) 16) | |
;; They changed this magic number at some point in time to reduce the | |
;; EV of each bet. See: | |
;; https://github.com/MindingTheData/Crash-Analysis/issues/1 | |
magic-immediate-crash-number 20] | |
(if (divisible? game-hash magic-immediate-crash-number) | |
1.0 | |
(/ (Math/floor (/ (- (* 100 e) h) (- e h))) | |
100.0)))) | |
(defn all-game-hashes | |
"A lazy sequence of all game hashes in reverse chronological order from | |
`recent-hash` all the way back to the first game hash." | |
[recent-hash] | |
(let [first-game-hash (str "77b271fe12fca03c618f63dfb79d4105" | |
"726ba9d4a25bb3f1964e435ccf9cb209")] | |
(concat | |
(->> recent-hash | |
(iterate sha/sha256) | |
(take-while #(not= % first-game-hash))) | |
[first-game-hash]))) | |
(comment | |
;; E.g. to generate the last million game hashes | |
(def games | |
(time | |
(->> "eeb2553823a150a584767d0dfa990f7fb96d88a125f0ecf773ffed104de2c472" | |
all-game-hashes | |
(take 1000000) | |
(into [])))) | |
; "Elapsed time: 4144.176054 msecs" | |
;; The last 10 game crash points | |
(->> games | |
(take 10) | |
(mapv (fn [gh] {:crash-point (crash-point gh) :game gh}))) | |
;=> [{:crash-point 32.64, :game "eeb2553823a150a584767d0dfa990f7fb96d88a125f0ecf773ffed104de2c472"} | |
; {:crash-point 4.69, :game "08c8e0d47b16703c1a3ab72f605732fb2850597969d28d7d14f63f36beae133a"} | |
; {:crash-point 2.44, :game "763d38cac9a5e56dc0ed51f0e6cf47544ebd3817aa96a94e071432a02d33a88b"} | |
; {:crash-point 1.29, :game "96dce54f6d7e9f12bd9b4ad3429685395dfa94464aa4f189755ed5861a4294a8"} | |
; {:crash-point 1.03, :game "cad42a35d39c789c0f006726c5eaf7a44a2cb28c56fc666f9f687dd8cde309eb"} | |
; {:crash-point 138.85, :game "eaf49bc33178ceae91f50df199d86129fd834958c9b5295bda8f3530647acc36"} | |
; {:crash-point 13.05, :game "cdb0cbd6f6b36c0ed26f3ad8b58feaf18cba6650e858d54030af175a56be5b28"} | |
; {:crash-point 1.09, :game "4e5108c551e339c50a6631a7040c3f74a3310a6f10733947c8e50aefd55abcf8"} | |
; {:crash-point 4.51, :game "2d5ced83236b0e30ef79250616d0539f531d1b1fd59d8e1cd5ded1e96c168ddd"} | |
; {:crash-point 9.8, :game "3d37d4908eb86710af0907ce34a57d1199cf41bab63e6ee05c0737e20ad729ca"}] | |
) | |
;;; For checking historical expected values | |
(defn hist-ev | |
"The expected value per bet of betting to cash out at `multiplier` over the | |
given `games` hashes." | |
[multiplier games] | |
(/ (->> games | |
(map | |
(fn [game] | |
(if (>= (crash-point game) multiplier) | |
multiplier | |
0))) | |
(apply +)) | |
(double (count games)))) | |
(comment | |
;; What's the historical EV over the last 10,000 games betting on 2x, 20x, | |
;; and 200x? | |
(def games | |
(->> "eeb2553823a150a584767d0dfa990f7fb96d88a125f0ecf773ffed104de2c472" | |
all-game-hashes | |
(into [] (take 10000)))) | |
(hist-ev 2 games) | |
;=> 0.947 | |
(hist-ev 20 games) | |
;=> 0.866 | |
(hist-ev 200 games) | |
;=> 0.8 | |
(hist-ev 2000 games) | |
;=> 0.4 | |
(hist-ev 20000 games) | |
;=> 2.0 | |
;; Does that mean betting on larger multipliers has a positive theoretical | |
;; EV? No; the expected value per bet is always negative, but if you bet on | |
;; large enough payouts, you can "overfit" your strategy to accomplish the | |
;l equivalent of quitting when you're ahead. | |
) | |
;;; For simulating betting strategies | |
(defn build-summary [summary {:keys [win? usd multiplier]}] | |
(if win? | |
(-> summary | |
(update :wins (fnil inc 1)) | |
(update :pnl (fnil + 0M) (* usd (dec multiplier)))) | |
(-> summary | |
(update :losses (fnil inc 0)) | |
(update :pnl (fnil - 0M) usd)))) | |
(defn simulate [strategy games & {:keys [bankroll take-profit stop-loss]}] | |
(reduce | |
(fn [{:keys [bets summary] :as x} game] | |
(let [bet (strategy bets game) | |
{:keys [pnl] :as summary} (build-summary summary bet) | |
x (assoc x :bets (cons bet bets) :summary summary)] | |
(if (or | |
;; Bankroll exhausted | |
(and bankroll (>= (- pnl) bankroll)) | |
;; Take profit limit hit | |
(and take-profit (>= pnl take-profit)) | |
;; Stop loss hit | |
(and stop-loss (< pnl stop-loss))) | |
(reduced x) | |
x))) | |
{:bets (list) | |
:summary {:wins 0 :losses 0 :pnl 0}} | |
games)) | |
(defn bet [game {:keys [usd multiplier] :as b}] | |
(let [cp (crash-point game)] | |
(assoc b :win? (<= multiplier cp) :cp cp))) | |
(comment | |
;; E.g. simulating a modified martingale strategy over the last thousand | |
;; games. The strategy starts with a bankroll of 100 USD and bets on a | |
;; multiplier of 4. | |
;; | |
;; A martingale strategy initially bets e.g. $0.10, and if it loses it doubles | |
;; its bet size, resetting it to $0.10 if it wins. The modification here is | |
;; that we impose a max bet size limit of $10 to avoid crazy exponential | |
;; growth. | |
(defn martingale' [[prev-game] game] | |
(bet | |
game | |
{:usd (if (and prev-game (not (:win? prev-game))) | |
(min (* (:usd prev-game) 2M) 10M) | |
0.1M) | |
:multiplier 4})) | |
(def last-thousand | |
(->> "eeb2553823a150a584767d0dfa990f7fb96d88a125f0ecf773ffed104de2c472" | |
all-game-hashes | |
(take 1000) | |
(reverse))) | |
(def results (simulate martingale' last-thousand :bankroll 100M)) | |
(dissoc results :bets) | |
;=> {:summary {:wins 157, :losses 549, :pnl -101.4M}} | |
;; PnL and win/loss with each bet made throughout the session | |
(->> (reverse (:bets results)) | |
(reductions build-summary {}) | |
rest | |
(take 10)) | |
;=> ({:losses 1, :pnl -0.1M} | |
; {:losses 2, :pnl -0.3M} | |
; {:losses 3, :pnl -0.7M} | |
; {:losses 3, :pnl 1.7M, :wins 2} | |
; {:losses 4, :pnl 1.6M, :wins 2} | |
; {:losses 5, :pnl 1.4M, :wins 2} | |
; {:losses 6, :pnl 1.0M, :wins 2} | |
; {:losses 7, :pnl 0.2M, :wins 2} | |
; {:losses 7, :pnl 5.0M, :wins 3} | |
; {:losses 8, :pnl 4.9M, :wins 3}) | |
;; Max P&L during the session | |
(->> (reverse (:bets results)) | |
(reductions build-summary {}) | |
rest | |
(map :pnl) | |
(apply max)) | |
;=> 256.4M | |
) |
0.23
i need 1x bet crash predictor
aviator crush game algorithm
how can i code a predictor
Crash game algorithme
أحتاج إلى 1x توقع تحطم الرهان
1
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how ican run it