From e34b3a9a02e1da1eb441f5b042c22be17e97755e Mon Sep 17 00:00:00 2001 From: Carles Tubio Date: Wed, 18 Sep 2024 04:54:23 +0000 Subject: [PATCH] Updated Coinbase integration to Advanced Trade API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ████ ███ To request new features or in case this commit breaks something for you, ████ ███ please, create a new github issue with all possible information for me, ▓███▀█▄ but never share your API Keys! ▒▓██ ███ ░▒▓█ ███ Signed-off-by: Carles Tubio _________________________________________ / Hello, WORLD! \ | | \ pssst.. 1.00000000 BTC = 54311.02 EUR. / ----------------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || --- .github/FUNDING.yml | 1 - Makefile | 45 ++++-------- README.md | 37 ++++++---- etc/Dockerfile | 2 +- etc/K.sh.dist | 59 ++++++++-------- src/bin/scaling-bot/scaling-bot.ansi.h | 4 -- src/bin/scaling-bot/scaling-bot.data.h | 18 ++--- src/bin/stable--bot/stable--bot.data.h | 12 ++-- src/bin/trading-bot/trading-bot.data.h | 38 +++++------ src/bin/trading-bot/trading-bot.test.h | 20 +++--- src/lib/Krypto.ninja-apis.h | 72 +++++++++++--------- src/lib/Krypto.ninja-bots.h | 69 ++++++++++--------- src/lib/Krypto.ninja-client/Makefile | 8 +-- src/lib/Krypto.ninja-client/www/js/Models.ts | 6 +- src/lib/Krypto.ninja-data.h | 51 ++++++++++---- src/lib/Makefile | 37 +++++----- 16 files changed, 251 insertions(+), 228 deletions(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 0cda1a501..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: ctubio diff --git a/Makefile b/Makefile index 0928daed4..d628ed154 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ K ?= K.sh MAJOR = 0 -MINOR = 6 -PATCH = 6 -BUILD = 6 +MINOR = 7 +PATCH = 0 +BUILD = 0 OBLIGATORY = DISCLAIMER: This is strict non-violent software: \n$\ if you hurt other living creatures, please stop; \n$\ @@ -18,7 +18,7 @@ SOURCE := $(filter-out trading-bot,$(notdir $(wildcard src/bin/*))) trading-b CARCH = x86_64-linux-gnu \ arm-linux-gnueabihf \ aarch64-linux-gnu \ - x86_64-apple-darwin20.4 \ + x86_64-apple-darwin23.5 \ x86_64-w64-mingw32 CHOST ?= $(or $(findstring $(shell test -n "`command -v g++`" && g++ -dumpmachine), \ @@ -33,12 +33,12 @@ KBUILD := build-$(KHOST) KHOME := $(if ${SYSTEMROOT},$(word 1,$(subst :, ,${SYSTEMROOT})):/,$(if \ $(findstring $(CHOST),$(lastword $(CARCH))),C:/,/var/lib/))K -ERR = *** K require g++ v10 or greater, but it was not found. +ERR = *** K require g++ v12 or greater, but it was not found. HINT := consider a symlink at /usr/bin/$(CHOST)-g++ pointing to your g++ executable STEP = $(shell tput setaf 2;tput setab 0)Building $(1)..$(shell tput sgr0) SUDO = $(shell test -n "`command -v sudo`" && echo sudo) -KARGS := -std=c++20 -O3 -pthread \ +KARGS := -std=c++23 -O3 -pthread \ -D'K_HOME="$(KHOME)"' -D'K_HEAD="$(shell \ git rev-parse HEAD 2>/dev/null || echo HEAD \ )"' -D'K_CHOST="$(KHOST)"' -D'K_SOURCE="K-$(KSRC)"' \ @@ -127,7 +127,7 @@ clean check lib: ifdef KALL unset KALL $(foreach chost,$(CARCH),&& $(MAKE) $@ CHOST=$(chost)) else - $(if $(shell ver="`$(CHOST)-g++ -dumpversion`" && test $${ver%%.*} -lt 10 && echo 1),$(warning $(ERR));$(error $(HINT))) + $(if $(shell ver="`$(CHOST)-g++ -dumpversion | cut -d'-' -f1`" && test $${ver%%.*} -lt 12 && echo 1),$(warning $(ERR));$(error $(HINT))) @$(MAKE) -C src/lib $@ CHOST=$(CHOST) KHOST=$(KHOST) KHOME=$(KHOME) endif @@ -155,28 +155,14 @@ ifdef KALL unset KALL $(foreach chost,$(CARCH),&& $(MAKE) $@ CHOST=$(chost)) else $(info $(call STEP,$(KSRC) $@ $(CHOST))) - $(if $(shell ver="`$(CHOST)-g++ -dumpversion`" && test $${ver%%.*} -lt 10 && echo 1),$(warning $(ERR));$(error $(HINT))) + $(if $(shell ver="`$(CHOST)-g++ -dumpversion | cut -d'-' -f1`" && test $${ver%%.*} -lt 12 && echo 1),$(warning $(ERR));$(error $(HINT))) @$(CHOST)-g++ --version @mkdir -p $(KBUILD)/bin - @$(MAKE) symbol_encode_$@ -s $(MAKE) $(if $(findstring darwin,$(CHOST)),Darwin,$(if $(findstring mingw32,$(CHOST)),Win32,$(shell uname -s))) CHOST=$(CHOST) - @$(MAKE) symbol_decode_$@ -s @chmod +x $(KBUILD)/bin/K-$(KSRC)* @$(if $(findstring $(CHOST),$(firstword $(CARCH))),$(MAKE) system_install -s) endif -symbol_encode_src: - -@egrep ₿ src test -lR | xargs -r sed -i 's/₿/\\u20BF/g' - -symbol_decode_src: - -@egrep \\u20BF src test -lR | xargs -r sed -i 's/\\u20BF/₿/g' - -symbol_encode_Darwin: - -@egrep \\u20BF src -lR | xargs -r sed -i 's/\\\(u20BF\)/\1/g' - -symbol_decode_Darwin: - -@egrep u20BF src -lR | xargs -r sed -i 's/\(u20BF\)/\\\1/g' - Linux: src/lib/Krypto.ninja-main.cxx src/bin/$(KSRC)/$(KSRC).main.h ifdef GITHUB_ACTIONS @unset GITHUB_ACTIONS && $(MAKE) KCOV="--coverage" $@ @@ -191,18 +177,15 @@ else endif Darwin: src/lib/Krypto.ninja-main.cxx src/bin/$(KSRC)/$(KSRC).main.h - -@$(MAKE) symbol_encode_$@ -s $(CHOST)-g++ -s -DNDEBUG -o $(KBUILD)/bin/K-$(KSRC) -fvisibility=hidden -fvisibility-inlines-hidden \ - -msse4.1 -maes -mpclmul -mmacosx-version-min=10.13 -nostartfiles -rdynamic \ + -msse4.1 -maes -mpclmul -mmacosx-version-min=10.13 -nostartfiles -rdynamic \ $< $(KARGS) -ldl -framework SystemConfiguration -framework CoreFoundation - -@$(MAKE) symbol_decode_$@ -s Win32: src/lib/Krypto.ninja-main.cxx src/bin/$(KSRC)/$(KSRC).main.h - $(CHOST)-g++-posix -s -DNDEBUG -o $(KBUILD)/bin/K-$(KSRC).exe \ - -DCURL_STATICLIB \ - -DSIGUSR1=SIGABRT -DSIGPIPE=SIGABRT -DSIGQUIT=SIGBREAK \ - $< $(KARGS) -static -lstdc++ -lgcc \ - -lcrypt32 -lpsapi -luserenv -liphlpapi -lwldap32 -lws2_32 + $(CHOST)-g++-posix -s -DNDEBUG -o $(KBUILD)/bin/K-$(KSRC).exe \ + -DCURL_STATICLIB -DSIGUSR1=SIGABRT -DSIGPIPE=SIGABRT -DSIGQUIT=SIGBREAK \ + $< $(KARGS) -static -lstdc++ -lgcc -lole32 -lbcrypt -lcrypt32 \ + -lpsapi -luserenv -liphlpapi -lwldap32 -lws2_32 -ldbghelp download: curl -L https://github.com/ctubio/Krypto-trading-bot/releases/download/$(MAJOR).$(MINOR).x/K-$(MAJOR).$(MINOR).$(PATCH).$(BUILD)-$(KHOST).tar.gz | tar xz @@ -359,4 +342,4 @@ md5: src asandwich: @test "`whoami`" = "root" && echo OK || echo make it yourself! -.PHONY: all K $(SOURCE) hlep hepl help doc test src client client.o clean check lib download cleandb screen-help list screen start stop restart startall stopall restartall packages system_install uninstall install docker reinstall diff upgrade changelog test-c push MAJOR MINOR PATCH BUILD release md5 symbol_encode_src symbol_decode_src symbol_encode_Darwin symbol_decode_Darwin asandwich +.PHONY: all K $(SOURCE) hlep hepl help doc test src client client.o clean check lib download cleandb screen-help list screen start stop restart startall stopall restartall packages system_install uninstall install docker reinstall diff upgrade changelog test-c push MAJOR MINOR PATCH BUILD release md5 asandwich diff --git a/README.md b/README.md index 08dd15906..c7523a0e1 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,10 @@ [`K`](https://github.com/ctubio/Krypto-trading-bot) is a family of (very customizable) very low latency [market making](https://github.com/ctubio/Krypto-trading-bot/blob/master/doc/MANUAL.md#what-is-market-making) trading bots with a fully featured [web interface](https://github.com/ctubio/Krypto-trading-bot#web-ui).
It can place and cancel orders on one of the several [compatible exchanges](https://github.com/ctubio/Krypto-trading-bot#compatible-exchanges) in less than a few milliseconds per order on a decent machine. -If you don't want to configure or hardcode your own trading strategies in your own machine,
you can run strategies from someone else at [kryll.io](https://kryll.io/) (or at any other trading community out there). - -If you don't want to run a bot at all,
you can fund liquidity pools at [tinyman.org](https://tinyman.org/) (or at any other defi out there). +If you don't want to configure or hardcode your own trading strategies in your own machine, or if you don't want to run a bot at all,
+you can fund liquidity pools of automated market makers at [tinyman.org](https://tinyman.org/) (or at any other defi out there), just remember: +- never write on any defi website your private keys (you have to sign transactions, not to share the keys of your wallet) +- never tell anyone on any chat your private keys (if you have questions, use a public forum and ignore private messages) ### Latest version at https://github.com/ctubio/Krypto-trading-bot @@ -23,7 +24,7 @@ If you don't want to run a bot at all,
you can fund liquidity pools at [tin [![Last Commit](https://img.shields.io/github/last-commit/ctubio/Krypto-trading-bot.svg)](https://github.com/ctubio/Krypto-trading-bot) [![Downloads Last Releases](https://img.shields.io/github/downloads/ctubio/Krypto-trading-bot/total.svg?label=downloads%20last%20releases)](https://github.com/ctubio/Krypto-trading-bot) -Our bots run on unix-like systems. Persistence is achieved through a built-in server-less SQLite C++ interface.
Data transfers are directly done from your machine to the exchange using the latest CURL and OpenSSL versions.
Installation in a dedicated [Debian](https://cdimage.debian.org/cdimage/release/current/), [Raspberry](https://www.raspberrypi.org/software/), [Red Hat](https://developers.redhat.com/products/rhel/download), [CentOS](https://wiki.centos.org/Download) or macOS instance without Docker is recommended. +Our bots run on unix-like systems. Persistence is achieved through a built-in server-less SQLite C++ interface.
Data transfers are directly done from your machine to the exchange using the latest CURL and OpenSSL versions.
Installation in a dedicated [Debian](https://cdimage.debian.org/cdimage/release/current/), [Raspberry](https://www.raspberrypi.com/software/), [Red Hat](https://developers.redhat.com/products/rhel/download), [CentOS](https://www.centos.org/download/) or macOS instance without Docker is recommended. ![Web UI Preview](https://user-images.githubusercontent.com/1634027/44740469-d5c7ff00-aafa-11e8-9252-73b9c1283adb.png) @@ -31,10 +32,11 @@ The web UI is compatible with most web browsers/resolutions, but Brave or Firefo ### Compatible Exchanges -||with Post-Only Orders support|without Post-Only| -|---|---|---| -|**with Maker and Taker fees**|[Coinbase](https://pro.coinbase.com/) ([fees](https://pro.coinbase.com/orders/fees))
⟿ _REST + WebSocket + FIX_

[Binance](https://www.binance.com/) ([fees](https://www.binance.com/en/fee/schedule))
⟿ _REST + WebSocket_

[Kraken](https://www.kraken.com/) ([fees](https://www.kraken.com/features/fee-schedule))
⟿ _REST + WebSocket²_

[KuCoin](https://www.kucoin.com/) ([fees](https://www.kucoin.com/vip/level))
⟿ _REST + WebSocket_

[Bitfinex](https://www.bitfinex.com/) ([fees](https://www.bitfinex.com/fees))
[Ethfinex](https://www.ethfinex.com/) ([fees](https://www.ethfinex.com/fees))
⟿ _REST + WebSocket_

[Gate.io](https://www.gate.io/) ([fees](https://www.gate.io/fee))
⟿ _REST + WebSocket_

[HitBTC](https://hitbtc.com/) ([fees](https://hitbtc.com/fee-tier))
[Bequant](https://bequant.io/) ([fees](https://bequant.io/fees-and-limits))
⟿ _REST + WebSocket²_

[Poloniex](https://www.poloniex.com/) ([fees](https://poloniex.com/fees/))
⟿ _REST + WebSocket_|*none*| -|**without Maker fees**|[BitMEX](https://www.bitmex.com/) ([fees](https://www.bitmex.com/app/fees))
⟿ _REST + WebSocket_|*none*| +If you ask me, is the best and most secure exchange by far, so here is my [referral link](https://advanced.coinbase.com/join/KAME9XG) for both of us to enjoy. + +In case you are looking for referral links to other exchanges, feel free to post a [new issue](https://github.com/ctubio/Krypto-trading-bot/issues/new?title=Referral%20link%20for%20%5Bexchange%5D) asking to other active users. + +
fully operationalmiraculously working (with known issues to be updated soon)
with Maker and Taker feesCoinbase (fees)
⟿ _REST + 2 WebSockets_
Binance (fees)
⟿ _REST + 1 WebSocket_

Kraken (fees)
⟿ _REST + 2 WebSockets_

KuCoin (fees)
⟿ _REST + 1 WebSocket_
Bitfinex (fees)
Ethfinex (fees)
⟿ _REST + 1 WebSocket_

Gate.io (fees)
⟿ _REST + 1 WebSocket_

HitBTC (fees)
Bequant (fees)
⟿ _REST + 2 WebSockets_

Poloniex (fees)
⟿ _REST + 1 WebSocket_
without Maker feesnoneBitMEX (fees)
⟿ _REST + 1 WebSocket_
All currency pairs are supported (use `--list` argument to see all currently tradable pairs on a given exchange). @@ -59,7 +61,7 @@ All currency pairs are supported (use `--list` argument to see all currently tra - [Cloud Hosting](#cloud-hosting) - Development - [Build notes](#build-notes) - - [Changelogs](#unreleased-changelog) + - [Changelogs](#changelog) - Humans and Milk Mammals - [Unlock](#unlock) - [Donations](#donations) @@ -76,7 +78,7 @@ See [etc/Dockerfile](https://github.com/ctubio/Krypto-trading-bot/tree/master/et Before starting with a manual installation, ensure your target machine has Windows 7 or greater and [MSYS2](https://www.msys2.org/) installed. -Use MSYS2 Terminal to install `make` (with command `pacman -S make`), and then proceed as usual with the installation. +Use MSYS2 Terminal to install `make` (with command `pacman -S make`), then proceed as usual with the installation. ### Manual GIT Installation @@ -254,7 +256,13 @@ js sandbox: [jsfiddle.net](https://jsfiddle.net) ws sandbox: [app.gosandy.io](https://app.gosandy.io/) -
Release v0.6.x Changelog +
Release v0.7.x Changelog + +Updated Coinbase integration to Advanced Trade API. + +
+ +
Release v0.6.x Changelog Added Hello World bot, Portfolios bot, Scaling bot and Stable bot. @@ -380,7 +388,9 @@ or donate your time with programming or financial suggestions in the IRC channel [IRC](https://kiwiirc.com/client/irc.libera.chat:6697/?theme=cli#krypto.ninja) is awesome! -but if you dislike it, consider to create a [new discussion](https://github.com/ctubio/Krypto-trading-bot/discussions) permanently readable by everybody. +But if you dislike it.. consider to join the [discord server](https://discord.gg/jAX7GEzcWD). Or you can DM [ctubio on reddit](https://www.reddit.com/user/ctubio) privately. + +Otherwise, here on GitHub, just create a [new discussion](https://github.com/ctubio/Krypto-trading-bot/discussions) permanently readable by everybody. ### Very Special Thanks to: @@ -438,7 +448,6 @@ Pull Requests are welcome, but adhere to the Contributor License Agreement: - https://youtu.be/1iZdJNH3Z1o - https://youtu.be/_e5hvHL2WTg - https://youtu.be/jQhtEYfax5c - - https://youtu.be/nmYOayNiv1A - add your song here (please open a [new issue](https://github.com/ctubio/Krypto-trading-bot/issues/new?title=Today,%20I%20sing) to share your link)



@@ -448,4 +457,4 @@ We have already enough policemen,
if you like adventures choose to be a


Violence
should not be the answer to those who
are asking for freedom.













- + 99999

+

diff --git a/etc/Dockerfile b/etc/Dockerfile index f031dacdc..eb7a741dd 100644 --- a/etc/Dockerfile +++ b/etc/Dockerfile @@ -22,7 +22,7 @@ ENV API_EXCHANGE NULL ENV API_CURRENCY BTC/USD ENV API_KEY NULL ENV API_SECRET NULL -ENV API_PASSPHRASE NULL +ENV API_KEY_ID NULL ENV K_BINARY_FILE K-trading-bot diff --git a/etc/K.sh.dist b/etc/K.sh.dist index 04b42b201..e469d1694 100644 --- a/etc/K.sh.dist +++ b/etc/K.sh.dist @@ -20,11 +20,11 @@ # █ K_BINARY_FILE . # ██ - Allows one executable file available on any PATH. # ██ . -#K_BINARY_FILE=K-+portfolios (under development) -#K_BINARY_FILE=K-hello-world -#K_BINARY_FILE=K-scaling-bot -#K_BINARY_FILE=K-stable--bot -K_BINARY_FILE=K-trading-bot +#K_BINARY_FILE="K-+portfolios" +#K_BINARY_FILE="K-hello-world" +#K_BINARY_FILE="K-scaling-bot" +#K_BINARY_FILE="K-stable--bot" +K_BINARY_FILE="K-trading-bot" # ██ . # ██▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ # ▌____ . @@ -44,45 +44,50 @@ OPTIONAL_ARGUMENTS="--colors --naked --heartbeat" # █ API_EXCHANGE . # ██ - Allows only one of the following exchanges below. # ██ . -#API_EXCHANGE=COINBASE -#API_EXCHANGE=BINANCE -#API_EXCHANGE=KRAKEN -#API_EXCHANGE=BITMEX -#API_EXCHANGE=KUCOIN -#API_EXCHANGE=BITFINEX -#API_EXCHANGE=BITFINEX_MARGIN -#API_EXCHANGE=ETHFINEX -#API_EXCHANGE=ETHFINEX_MARGIN -#API_EXCHANGE=GATEIO -#API_EXCHANGE=HITBTC -#API_EXCHANGE=BEQUANT -#API_EXCHANGE=POLONIEX +#API_EXCHANGE="COINBASE" +#API_EXCHANGE="BINANCE" +#API_EXCHANGE="KRAKEN" +#API_EXCHANGE="BITMEX" +#API_EXCHANGE="KUCOIN" +#API_EXCHANGE="BITFINEX" +#API_EXCHANGE="BITFINEX_MARGIN" +#API_EXCHANGE="ETHFINEX" +#API_EXCHANGE="ETHFINEX_MARGIN" +#API_EXCHANGE="GATEIO" +#API_EXCHANGE="HITBTC" +#API_EXCHANGE="BEQUANT" +#API_EXCHANGE="POLONIEX" # ▌____________________________________________________. # █ API_CURRENCY . # ██ - Allows any currency pair (with format "AAA/ZZZ"). # ██ (see the website of the exchange for all symbols). # ██ . -#API_CURRENCY=BTC/EUR +#API_CURRENCY="BTC/EUR" # ▌____________________________________________________. # █ API_KEY . # ██ - Allows any valid API KEY (never share!) . # ██ (see the website of the exchange please) . +# ██ (on COINBASE is called API KEY NAME, and . +# ██ is only visible while creating the keys) . # ██ . -#API_KEY=exampleapikey +#API_KEY="cdp_exampleapikey" # ▌____________________________________________________. # █ API_SECRET . # ██ - Allows any valid API SECRET (never share!) . # ██ (see the website of the exchange thank you) . +# ██ (must be one line, as UUID or EC PKEY cert) . # ██ . -#API_SECRET=exampleapisecret +#API_SECRET="-----BEGIN EC PRIVATE KEY-----\nexampleapisecret\n-----END EC PRIVATE KEY-----\n" # ▌____________________________________________________. -# █ API_PASSPHRASE . -# ██ - Allows any valid API PASSPHRASE (never share!) . -# ██ (only COINBASE/KUCOIN must have API PASSPHRASE) . +# █ API_KEY_ID . +# ██ - Allows any valid API KEY ID (never share!) . +# ██ (only COINBASE/KUCOIN must have API_KEY_ID) . # ██ (can be safely ignored for all other exchanges) . # ██ (see the website of COINBASE/KUCOIN for + info) . +# ██ (from COINBASE it can be copy&pasted anytime, but. +# ██ on KUCOIN is named PASSPHRASE because of reasons). # ██ . -#API_PASSPHRASE=exampleapipassphrase +#API_KEY_ID="exampleapikeyid" # ██ . # ██▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ # ▌____ . @@ -94,8 +99,8 @@ OPTIONAL_ARGUMENTS="--colors --naked --heartbeat" --exchange ${API_EXCHANGE:-""} \ --currency ${API_CURRENCY:-""} \ --apikey ${API_KEY:-""} \ - --secret ${API_SECRET:-""} \ - --passphrase ${API_PASSPHRASE:-""} \ + --secret "${API_SECRET:-""}" \ + --apikeyid ${API_KEY_ID:-""} \ $OPTIONAL_ARGUMENTS "$@" ; # ▌ ___________________________________________________. # █ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯. diff --git a/src/bin/scaling-bot/scaling-bot.ansi.h b/src/bin/scaling-bot/scaling-bot.ansi.h index 24e3d5a6b..cb8baa14c 100644 --- a/src/bin/scaling-bot/scaling-bot.ansi.h +++ b/src/bin/scaling-bot/scaling-bot.ansi.h @@ -21,7 +21,3 @@ //! \def //! \brief Define color yellow as green. #define ANSI_YELLOW "2" - -//! \def -//! \brief Define color cyan as blue. -#define ANSI_CYAN "4" diff --git a/src/bin/scaling-bot/scaling-bot.data.h b/src/bin/scaling-bot/scaling-bot.data.h index 0f9cee3ca..a7cd8fe6c 100644 --- a/src/bin/scaling-bot/scaling-bot.data.h +++ b/src/bin/scaling-bot/scaling-bot.data.h @@ -59,11 +59,11 @@ namespace analpaper { void read_from_gw(const Order &order) { pongs.maxmin(order); if (order.orderId.empty()) return; - last->justFilled = !order.isPong + last->qtyFilled = !order.isPong and order.status == Status::Terminated - and order.quantity == order.totalFilled + and order.quantity == order.qtyFilled ? order.quantity : 0; - if (last->justFilled + if (last->qtyFilled or (order.isPong and order.status == Status::Working) ) K.log("GW " + K.gateway->exchange, string(order.side == Side::Bid @@ -538,14 +538,14 @@ namespace analpaper { }; void scale() { if (orders.last - and orders.last->justFilled + and orders.last->qtyFilled and K.arg("pong-width") ) pending.push_back({ orders.last->side == Side::Bid ? Side::Ask : Side::Bid, orders.calcPongPrice(levels.fairValue), - orders.last->justFilled, + orders.last->qtyFilled, Tstamp, true, K.gateway->randId() @@ -572,10 +572,10 @@ namespace analpaper { K.log("QE", "Canceled " + to_string(n) + " open order" + string(n != 1, 's') + " before quit"); }; private: - bool abandon(const Order &order, System::Quote "e) { + bool abandon(const Order &order, const Price ¤tPrice, System::Quote "e) { if (orders.zombies.stillAlive(order)) { if (order.status == Status::Waiting - or abs(order.price - quote.price) < K.gateway->tickPrice + or abs(order.price - currentPrice) < K.gateway->tickPrice or (K.arg("lifetime") and order.time + K.arg("lifetime") > Tstamp) ) quote.skip(); else return true; @@ -584,9 +584,9 @@ namespace analpaper { }; vector abandon(System::Quote "e) { vector abandoned; - const bool all = quote.state != QuoteState::Live; + const Price currentPrice = quote.price; for (Order *const it : orders.at(quote.side)) - if (all or abandon(*it, quote)) + if (!currentPrice or abandon(*it, currentPrice, quote)) abandoned.push_back(it); return abandoned; }; diff --git a/src/bin/stable--bot/stable--bot.data.h b/src/bin/stable--bot/stable--bot.data.h index 610b8e240..b57d9f3f5 100644 --- a/src/bin/stable--bot/stable--bot.data.h +++ b/src/bin/stable--bot/stable--bot.data.h @@ -32,13 +32,13 @@ namespace analpaper { , K(bot) {}; void read_from_gw(const Order &order) { - if (!order.orderId.empty() and order.justFilled) + if (!order.orderId.empty() and order.qtyFilled == order.quantity and order.status == Status::Terminated) K.log("GW " + K.gateway->exchange, string(order.side == Side::Bid ? ANSI_HIGH_CYAN + "TRADE BUY " : ANSI_PUKE_MAGENTA + "TRADE SELL " ) - + K.gateway->decimal.amount.str(order.justFilled) + + K.gateway->decimal.amount.str(order.quantity) + " " + K.gateway->base + " at " + K.gateway->decimal.price.str(order.price) + " " + K.gateway->quote); @@ -304,10 +304,10 @@ namespace analpaper { K.log("QE", "Canceled " + to_string(n) + " open order" + string(n != 1, 's') + " before quit"); }; private: - bool abandon(const Order &order, System::Quote "e) { + bool abandon(const Order &order, const Price ¤tPrice, System::Quote "e) { if (orders.zombies.stillAlive(order)) { if (order.status == Status::Waiting - or abs(order.price - quote.price) < K.gateway->tickPrice + or abs(order.price - currentPrice) < K.gateway->tickPrice or (K.arg("lifetime") and order.time + K.arg("lifetime") > Tstamp) ) quote.skip(); else return true; @@ -316,9 +316,9 @@ namespace analpaper { }; vector abandon(System::Quote "e) { vector abandoned; - const bool all = quote.state != QuoteState::Live; + const Price currentPrice = quote.price; for (Order *const it : orders.at(quote.side)) - if (all or abandon(*it, quote)) + if (!currentPrice or abandon(*it, currentPrice, quote)) abandoned.push_back(it); return abandoned; }; diff --git a/src/bin/trading-bot/trading-bot.data.h b/src/bin/trading-bot/trading-bot.data.h index 6511dd4c2..b04feab74 100644 --- a/src/bin/trading-bot/trading-bot.data.h +++ b/src/bin/trading-bot/trading-bot.data.h @@ -1147,12 +1147,12 @@ namespace tribeca { OrderFilled filled = { last.side, last.price, - last.justFilled, + last.qtyFilled, time, to_string(time), K.gateway->margin == Future::Spot - ? abs(last.price * last.justFilled) - : last.justFilled, + ? abs(last.price * last.qtyFilled) + : last.qtyFilled, fee, 0, 0, 0, 0, 0, last.isPong, @@ -1341,7 +1341,7 @@ namespace tribeca { : sells ).insert(pair( last.price, - RecentTrade(last.price, last.justFilled) + RecentTrade(last.price, last.qtyFilled) )); }; void expire() { @@ -1702,7 +1702,7 @@ namespace tribeca { calcHeldAmount(orders.last->side); calcFundsSilently(); } - if (orders.last->justFilled) + if (orders.last->qtyFilled) safety.insertTrade(*orders.last); }; mMatter about() const override { @@ -2536,30 +2536,24 @@ namespace tribeca { return false; }; private: - bool abandon(const Order &order, System::Quote "e, unsigned int &bullets) { + bool abandon(const Order &order, const Price ¤tPrice, System::Quote "e, unsigned int &limit) { if (orders.zombies.stillAlive(order)) { - if (abs(order.price - quote.price) < K.gateway->tickPrice) - quote.skip(); - else if (order.status == Status::Waiting) { - if (qp.safety != QuotingSafety::AK47 - or !--bullets - ) quote.skip(); - } else if (qp.safety != QuotingSafety::AK47 - or quote.deprecates(order.price) - ) { - if (qp.lifetime and order.time + qp.lifetime > Tstamp) - quote.skip(); - else return true; - } + if ((order.status == Status::Waiting + or abs(order.price - currentPrice) < K.gateway->tickPrice + or (qp.lifetime and order.time + qp.lifetime > Tstamp) + ) and (qp.safety != QuotingSafety::AK47 + or (!limit or !--limit) + )) quote.skip(); + else return true; } return false; }; vector abandon(System::Quote "e) { vector abandoned; - unsigned int bullets = qp.bullets; - const bool all = quote.state != QuoteState::Live; + unsigned int limit = qp.bullets; + const Price currentPrice = quote.price; for (Order *const it : orders.at(quote.side)) - if (all or abandon(*it, quote, bullets)) + if (!currentPrice or abandon(*it, currentPrice, quote, limit)) abandoned.push_back(it); return abandoned; }; diff --git a/src/bin/trading-bot/trading-bot.test.h b/src/bin/trading-bot/trading-bot.test.h index af9b4becd..1e0d07153 100644 --- a/src/bin/trading-bot/trading-bot.test.h +++ b/src/bin/trading-bot/trading-bot.test.h @@ -143,21 +143,21 @@ SCENARIO_METHOD(TradingBot, "ANY BTC/EUR") { WHEN("assigned") { Order order; REQUIRE_NOTHROW(order.price = 1234.57); - REQUIRE_NOTHROW(order.justFilled = 0.01234566); + REQUIRE_NOTHROW(order.qtyFilled = 0.01234566); REQUIRE_NOTHROW(order.side = Side::Ask); REQUIRE_NOTHROW(engine.wallet.safety.recentTrades.insert(order)); REQUIRE_NOTHROW(order.price = 1234.58); - REQUIRE_NOTHROW(order.justFilled = 0.01234567); + REQUIRE_NOTHROW(order.qtyFilled = 0.01234567); REQUIRE_NOTHROW(engine.wallet.safety.recentTrades.insert(order)); REQUIRE_NOTHROW(order.price = 1234.56); - REQUIRE_NOTHROW(order.justFilled = 0.12345678); + REQUIRE_NOTHROW(order.qtyFilled = 0.12345678); REQUIRE_NOTHROW(order.side = Side::Bid); REQUIRE_NOTHROW(engine.wallet.safety.recentTrades.insert(order)); REQUIRE_NOTHROW(order.price = 1234.50); - REQUIRE_NOTHROW(order.justFilled = 0.12345679); + REQUIRE_NOTHROW(order.qtyFilled = 0.12345679); REQUIRE_NOTHROW(engine.wallet.safety.recentTrades.insert(order)); REQUIRE_NOTHROW(order.price = 1234.60); - REQUIRE_NOTHROW(order.justFilled = 0.12345678); + REQUIRE_NOTHROW(order.qtyFilled = 0.12345678); REQUIRE_NOTHROW(order.side = Side::Ask); REQUIRE_NOTHROW(engine.wallet.safety.recentTrades.insert(order)); THEN("values") { @@ -457,8 +457,8 @@ SCENARIO_METHOD(TradingBot, "ANY BTC/EUR") { REQUIRE_NOTHROW(engine.broker.semaphore.click({ {"agree", 0} })); - REQUIRE_NOTHROW(engine.broker.quotes.bid.skip(QuoteState::MissingData)); - REQUIRE_NOTHROW(engine.broker.quotes.ask.skip(QuoteState::MissingData)); + REQUIRE_NOTHROW(engine.broker.quotes.bid.skip(QuoteState::UnknownReason)); + REQUIRE_NOTHROW(engine.broker.quotes.ask.skip(QuoteState::UnknownReason)); REQUIRE(engine.broker.quotes.bid.empty()); REQUIRE(engine.broker.quotes.ask.empty()); REQUIRE_FALSE(engine.broker.ready()); @@ -593,7 +593,7 @@ SCENARIO_METHOD(TradingBot, "ANY BTC/EUR") { stringstream ss(line); string _, pingpong, side; Order order; - ss >> _ >> _ >> _ >> _ >> pingpong >> _ >> side >> order.justFilled >> _ >> _ >> _ >> order.price; + ss >> _ >> _ >> _ >> _ >> pingpong >> _ >> side >> order.qtyFilled >> _ >> _ >> _ >> order.price; order.side = (side == "BUY" ? Side::Bid : Side::Ask); order.isPong = (pingpong == "PONG"); return order; @@ -617,8 +617,8 @@ SCENARIO_METHOD(TradingBot, "ANY BTC/EUR") { WHEN("cumulated cross pongs") { for (const auto &order : loglines) { baseSign = (order.side == Side::Bid) ? 1 : -1; - expectedBaseDelta += baseSign * order.justFilled; - expectedQuoteDelta -= baseSign * order.justFilled * order.price; + expectedBaseDelta += baseSign * order.qtyFilled; + expectedQuoteDelta -= baseSign * order.qtyFilled * order.price; this_thread::sleep_for(chrono::milliseconds(2)); engine.wallet.safety.trades.insert(order); Amount actualBaseDelta = 0; diff --git a/src/lib/Krypto.ninja-apis.h b/src/lib/Krypto.ninja-apis.h index d8c1c2755..c2fb6974e 100644 --- a/src/lib/Krypto.ninja-apis.h +++ b/src/lib/Krypto.ninja-apis.h @@ -132,8 +132,7 @@ namespace ₿ { string orderId = "", exchangeId = ""; Status status = (Status)0; - Amount justFilled = 0; - Amount totalFilled = 0; + Amount qtyFilled = 0; OrderType type = (OrderType)0; TimeInForce timeInForce = (TimeInForce)0; bool manual = false; @@ -143,11 +142,10 @@ namespace ₿ { if (Status::Working == ( order->status = raw.status ) and !order->latency) order->latency = raw.time - order->time; order->time = raw.time; - order->justFilled = raw.justFilled; - order->totalFilled += raw.justFilled; if (!raw.exchangeId.empty()) order->exchangeId = raw.exchangeId; if (raw.price) order->price = raw.price; if (raw.quantity) order->quantity = raw.quantity; + if (raw.qtyFilled) order->qtyFilled = raw.qtyFilled; } return order; }; @@ -298,9 +296,9 @@ namespace ₿ { class GwExchange: public GwExchangeData { public: using Report = vector>; - string exchange, apikey, secret, pass, + string exchange, apikey, secret, apikeyid, base, quote, symbol, - http, ws, fix, + http, ws, unlock; Price tickPrice = 0; Amount tickSize = 0, @@ -578,12 +576,15 @@ namespace ₿ { while (accept_msg(WebSocketTwin::unframe())); }; }; - class GwApiWsFix: public GwApiWs, - public Curl::FixSocket { + +class GwApiWsFix: public GwApiWs, + public Curl::FixSocket { public: GwApiWsFix(const string &t) : FixSocket(t, apikey, guard) {}; + private: + string fix; protected: bool connected() const override { return GwApiWs::connected() @@ -786,7 +787,7 @@ namespace ₿ { }; protected: string nonce() const override { - return to_string((Clock)(Tstamp / 1e+3)); + return to_string(Tstamp / 1e+3); }; void pairs(string &report) const override { const json reply = Curl::Web::xfer(*guard, http + "/spot/currency_pairs"); @@ -892,39 +893,43 @@ namespace ₿ { webOrders = "https://bequant.io/reports/orders"; }; }; - class GwCoinbase: public GwApiWsFix { + class GwCoinbase: public GwApiWsWs { public: GwCoinbase() - : GwApiWsFix("Coinbase") { - http = "https://api.pro.coinbase.com"; - ws = "wss://ws-feed.pro.coinbase.com"; - fix = "fix.pro.coinbase.com:4198"; + http = "https://api.coinbase.com/api/v3/brokerage"; + ws = "wss://advanced-trade-ws.coinbase.com"; randId = Random::uuid36Id; - webMarket = "https://pro.coinbase.com/trade/"; - webOrders = "https://pro.coinbase.com/orders/"; + webMarket = "https://www.coinbase.com/advanced-trade/spot/"; + webOrders = "https://www.coinbase.com/orders/"; }; string web(const string &base, const string "e) const { return webMarket + base + "-" + quote; }; protected: +//BO non-free Gw class member functions from lib build-*/lib/K-*.a (it just redefines all virtual gateway functions below). +/**/ virtual string token(const string &crud = "", const string &url = "") const = 0; // return logon message. +//EO non-free Gw class member functions from lib build-*/lib/K-*.a (it just redefines all virtual gateway functions above). string nonce() const override { - return to_string(Tstamp / 1e+3); + return Random::char16Id(); }; void pairs(string &report) const override { - const json reply = Curl::Web::xfer(*guard, http + "/products"); - if (!reply.is_array() + const json reply = xfer(http + "/products"); + if (!reply.is_object() or reply.empty() - or !reply.at(0).is_object() - or !reply.at(0).contains("base_currency") - or !reply.at(0).contains("quote_currency") + or !reply.contains("products") + or !reply.at("products").is_array() + or reply.at("products").empty() + or !reply.at("products").at(0).is_object() + or !reply.at("products").at(0).contains("base_currency_id") + or !reply.at("products").at(0).contains("quote_currency_id") ) print("Error while reading pairs: " + reply.dump()); - else for (const json &it : reply) + else for (const json &it : reply.at("products")) if (!it.value("trading_disabled", true) and it.value("status", "") == "online") - report += it.value("base_currency", "") + "/" + it.value("quote_currency", "") + ANSI_NEW_LINE; + report += it.value("base_currency_id", "") + "/" + it.value("quote_currency_id", "") + ANSI_NEW_LINE; }; json handshake() const override { - const json reply = Curl::Web::xfer(*guard, http + "/products/" + base + "-" + quote); + const json reply = xfer(http + "/products/" + base + "-" + quote); return { { "base", base }, { "quote", quote }, @@ -935,14 +940,15 @@ namespace ₿ { { "reply", reply } }; }; - json xfer(const string &url, const string &h1, const string &h2, const string &h3, const string &h4, const string &crud) const { - return Curl::Web::xfer(*guard, url, crud, "", { - "CB-ACCESS-KEY: " + h1, - "CB-ACCESS-SIGN: " + h2, - "CB-ACCESS-TIMESTAMP: " + h3, - "CB-ACCESS-PASSPHRASE: " + h4 - }); + string twin(const string &ws) const override { + return string(ws).insert(ws.find("ws.") + 2, "-user"); }; + json xfer(const string &url, const string &post = "", const string &crud = "GET") const { + return Curl::Web::xfer(*guard, url, crud, post, { + "Content-Type: application/json", + "Authorization: Bearer " + token(crud, url) + }); + }; }; class GwBitfinex: public GwApiWs { protected: @@ -1105,7 +1111,7 @@ namespace ₿ { time = nonce(), hash = time + crud + path, sign = Text::B64(Text::HMAC256(hash, secret, true)), - code = Text::B64(Text::HMAC256(pass, secret, true)); + code = Text::B64(Text::HMAC256(apikeyid, secret, true)); const json reply = xfer(http + path, apikey, sign, code, time, crud); if (!reply.contains("code") or !reply.at("code").is_string() diff --git a/src/lib/Krypto.ninja-bots.h b/src/lib/Krypto.ninja-bots.h index 6e8956455..7052d2e6f 100644 --- a/src/lib/Krypto.ninja-bots.h +++ b/src/lib/Krypto.ninja-bots.h @@ -350,13 +350,12 @@ namespace ₿ { {"exchange", "NAME", "", "set exchange NAME for trading, mandatory"}, {"currency", "PAIR", "", "set currency PAIR for trading, use format ISO 4217-A3" ANSI_NEW_LINE "with '/' separator, like 'BTC/EUR', mandatory"}, - {"apikey", "WORD", "", "set (never share!) WORD as api key for trading, mandatory"}, + {"apikey", "WORD", "", "set (never share!) WORD as api key name for trading, mandatory"}, {"secret", "WORD", "", "set (never share!) WORD as api secret for trading, mandatory"}, - {"passphrase", "WORD", "", "set (never share!) WORD as api passphrase for trading"}, + {"apikeyid", "WORD", "", "set (never share!) WORD as api key id for trading"}, {"ENDPOINTS", "", nullptr, ""}, {"http", "URL", "", "set URL of alernative HTTPS api endpoint for trading"}, {"wss", "URL", "", "set URL of alernative WSS api endpoint for trading"}, - {"fix", "URL", "", "set URL of alernative FIX api endpoint for trading"}, {"NETWORK", "", nullptr, ""}, {"nocache", "1", nullptr, "do not cache handshakes 7 hours at " K_HOME "/cache"}, {"interface", "IP", "", "set IP to bind as outgoing network interface"}, @@ -503,6 +502,14 @@ namespace ₿ { args["currency"] = Text::strU(arg("currency")); args["base"] = arg("currency").substr(0, arg("currency").find("/")); args["quote"] = arg("currency").substr(1+ arg("currency").find("/")); + if (arg("secret").find("EC PRIVATE KEY") != string::npos && arg("secret").find(ANSI_NEW_LINE) == string::npos) { + string::size_type n = 0; + while ((n = arg("secret").find("\\r", n)) != string::npos) + args["secret"] = string(arg("secret")).erase(n, 2); + n = 0; + while ((n = arg("secret").find("\\n", n + 4)) != string::npos) + args["secret"] = string(arg("secret")).replace(n, 2, ANSI_NEW_LINE); + } if (!args.contains("leverage")) args["leverage"] = 1.0; if (!args.contains("min-size")) args["min-size"] = 0.0; if (!args.contains("maker-fee")) args["maker-fee"] = 0.0; @@ -1156,10 +1163,10 @@ namespace ₿ { enum class QuoteState: unsigned int { Disconnected, Live, Crossed, - MissingData, UnknownHeld, WidthTooHigh, - DepletedFunds, DisabledQuotes, WaitingFunds, + UnknownReason, DisabledQuotes, DepletedFunds, + WidthTooHigh, WaitingPing, WaitingFunds, UpTrendHeld, DownTrendHeld, - TBPHeld, MaxTradesSeconds, WaitingPing, + TBPHeld, MaxTradesSeconds, ScaleSided, ScalationLimit, DeviationLimit }; @@ -1168,35 +1175,34 @@ namespace ₿ { class Quote: public Level { public: const Side side = (Side)0; - QuoteState state = QuoteState::MissingData; + QuoteState state = QuoteState::UnknownReason; bool isPong = false; public: Quote(const Side &s) : side(s) {}; bool empty() const { - return !size or !price; + return !price or !size; }; void skip() { - size = 0; + price = size = 0; }; void skip(const QuoteState &reason) { - price = size = 0; + skip(); state = reason; }; - bool deprecates(const Price &otherPrice) const { + bool deprecates(const Price &otherPrice, Price currentPrice = 0) const { + if (!currentPrice) currentPrice = price; return side == Side::Bid - ? price < otherPrice - : price > otherPrice; + ? currentPrice < otherPrice + : currentPrice > otherPrice; }; - bool checkCrossed(const Quote &otherSide) { - if (empty()) return false; - if (otherSide.empty() or deprecates(otherSide.price)) { - state = QuoteState::Live; - return false; - } - state = QuoteState::Crossed; - return true; + void checkCrossed(const Quote &otherSide) { + if (!empty()) + state = ( + otherSide.empty() or deprecates(otherSide.price) + ) ? QuoteState::Live + : QuoteState::Crossed; }; }; class Quotes { @@ -1204,8 +1210,8 @@ namespace ₿ { Quote bid, ask; private: - QuoteState prevBidState = QuoteState::MissingData, - prevAskState = QuoteState::MissingData; + QuoteState prevBidState = QuoteState::UnknownReason, + prevAskState = QuoteState::UnknownReason; private_ref: const Option &K; public: @@ -1259,7 +1265,7 @@ namespace ₿ { void reset() { bid.isPong = ask.isPong = false; - states(QuoteState::UnknownHeld); + states(QuoteState::UnknownReason); }; void unset() { if (bid.price <= 0 or ask.price <= 0) { @@ -1269,8 +1275,11 @@ namespace ₿ { } }; void upset() { - if (bid.checkCrossed(ask) or ask.checkCrossed(bid)) - K.warn("QE", "Crossed bid/ask quotes detected, that is.. unexpected", 3e+3); + bid.checkCrossed(ask); + ask.checkCrossed(bid); + if (bid.state == QuoteState::Crossed + or ask.state == QuoteState::Crossed + ) K.warn("QE", "Crossed bid/ask quotes detected, that is.. unexpected", 3e+3); }; void log() { logState(bid, &prevBidState); @@ -1485,8 +1494,6 @@ namespace ₿ { gateway->http = K->arg("http"); if (!gateway->ws.empty() and !K->arg("wss").empty()) gateway->ws = K->arg("wss"); - if (!gateway->fix.empty() and !K->arg("fix").empty()) - gateway->fix = K->arg("fix"); if (K->arg("taker-fee")) gateway->takeFee = K->arg("taker-fee") / 1e+2; if (K->arg("maker-fee")) @@ -1496,7 +1503,7 @@ namespace ₿ { gateway->leverage = K->arg("leverage"); gateway->apikey = K->arg("apikey"); gateway->secret = K->arg("secret"); - gateway->pass = K->arg("passphrase"); + gateway->apikeyid = K->arg("apikeyid"); gateway->maxLevel = K->arg("market-limit"); gateway->debug = K->arg("debug-secret"); gateway->guard = &lock; @@ -1546,9 +1553,8 @@ namespace ₿ { if (orders->last) { if (orders->purgeable(*orders->last)) orders->purge(orders->last); - else orders->last->justFilled = 0; } - if (raw.justFilled) { + if (raw.qtyFilled == raw.quantity && raw.status == Status::Terminated) { gateway->askForBalance = true; make_computer_go->beep(); } @@ -1607,7 +1613,6 @@ namespace ₿ { handshake({ {"gateway", gateway->http }, {"gateway", gateway->ws }, - {"gateway", gateway->fix }, {"autoBot", arg("autobot") ? "yes" : "no" } diff --git a/src/lib/Krypto.ninja-client/Makefile b/src/lib/Krypto.ninja-client/Makefile index aa43ce466..963e78d00 100644 --- a/src/lib/Krypto.ninja-client/Makefile +++ b/src/lib/Krypto.ninja-client/Makefile @@ -24,14 +24,14 @@ STEP_4 := $(call STEP,4,css files) all $(KSRC): js css npm: package.json - @echo $(STEP_1) + $(info $(STEP_1)) @cd $(KHOME) && $@ install ifndef GITHUB_ACTIONS @rm $(KHOME)/$(basename $<)* endif lib: www/js npm - @echo $(STEP_2) + $(info $(STEP_2)) cp -R $< $(NODE_PATH)/$@ ls -1 $< | cut -d . -f1 | xargs -I % echo "export * as % from './%';" > $(NODE_PATH)/$@/K.ts $(TSC) $(NODE_PATH)/$@/*.ts @@ -47,11 +47,11 @@ $(KCLIENT)/.main.ts: $(KCLIENT) js: $(KCLIENT)/.main.ts lib $(TSC) --outDir $(KASSETS)/$@ $< @rm -v $< - @echo $(STEP_3) + $(info $(STEP_3)) $(BROWSERIFY) $(KASSETS)/$@/$(notdir $(basename $<)).$@ | uglifyjs | gzip > $(KASSETS)/$@/client.min.$@ css: www/css beacons - @echo $(STEP_4) + $(info $(STEP_4)) $(foreach x,$(wildcard $> $(KASSETS)/$@/bootstrap.min.$@ diff --git a/src/lib/Krypto.ninja-client/www/js/Models.ts b/src/lib/Krypto.ninja-client/www/js/Models.ts index 94d102b9b..8d5e1508b 100644 --- a/src/lib/Krypto.ninja-client/www/js/Models.ts +++ b/src/lib/Krypto.ninja-client/www/js/Models.ts @@ -191,10 +191,10 @@ export class TwoSidedQuote { export enum QuoteStatus { Disconnected, Live, Crossed, - MissingData, UnknownHeld, WidthTooHigh, - DepletedFunds, DisabledQuotes, WaitingFunds, + UnknownReason, DisabledQuotes, DepletedFunds, + WidthTooHigh, WaitingPing, WaitingFunds, UpTrendHeld, DownTrendHeld, - TBPHeld, MaxTradesSeconds, WaitingPing, + TBPHeld, MaxTradesSeconds, ScaleSided, ScalationLimit, DeviationLimit } diff --git a/src/lib/Krypto.ninja-data.h b/src/lib/Krypto.ninja-data.h index b0039ee76..3d643ae80 100644 --- a/src/lib/Krypto.ninja-data.h +++ b/src/lib/Krypto.ninja-data.h @@ -609,6 +609,7 @@ namespace ₿ { curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 21L); + // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); rc = curl_easy_perform(curl); curl_easy_cleanup(curl); if (slist) curl_slist_free_all(slist); @@ -616,7 +617,7 @@ namespace ₿ { return rc == CURLE_OK ? (json::accept(reply) ? json::parse(reply) - : json::object() + : (json){ {"error", "CURL unexpected server reply: " + reply} } ) : (json){ {"error", string("CURL Request Error: ") + curl_easy_strerror(rc)} }; }; @@ -668,8 +669,8 @@ namespace ₿ { } } } + curl_url_cleanup(url); } - curl_url_cleanup(url); return rc == CURLE_OK ? Easy::connect( "http" + uri.substr(2), @@ -734,7 +735,7 @@ namespace ₿ { }; }; }; - + class Text { public: static string strL(string input) { @@ -748,7 +749,9 @@ namespace ₿ { static string CRC32(const string &input) { return to_string(crc32(0, (const Bytef*)input.data(), input.length())); }; - static string B64(const string &input) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wrestrict" + static string B64(const string &input, const bool &urlsafe = false) { BIO *bio, *b64; BUF_MEM *bufferPtr; b64 = BIO_new(BIO_f_base64()); @@ -759,22 +762,44 @@ namespace ₿ { BIO_write(bio, input.data(), input.length()); if (BIO_flush(bio)) {} BIO_get_mem_ptr(bio, &bufferPtr); - const string output(bufferPtr->data, bufferPtr->length); + string output(bufferPtr->data, bufferPtr->length); BIO_free_all(bio); + if (urlsafe) { + string::size_type n = 0; + while ((n = output.find("+", n)) != string::npos) + output.replace(n++, 1, "-"); + n = 0; + while ((n = output.find("/", n)) != string::npos) + output.replace(n++, 1, "_"); + while (output.back() == '=') + output.erase(output.length() - 1); + } return output; }; - static string B64_decode(const string &input) { + static string B64_decode(const string &input, const bool &urlsafe = false) { + if (urlsafe) { + string output = input; + string::size_type n = 0; + while ((n = output.find("-", n)) != string::npos) + output.replace(n++, 1, "+"); + n = 0; + while ((n = output.find("_", n)) != string::npos) + output.replace(n++, 1, "/"); + output += string(4 - (output.length() % 4), '='); + return B64_decode(output + string(4 - (output.length() % 4), '=')); + } BIO *bio, *b64; - char output[input.length()]; + char out[input.length()]; b64 = BIO_new(BIO_f_base64()); bio = BIO_new_mem_buf(input.data(), input.length()); bio = BIO_push(b64, bio); if (BIO_set_close(bio, BIO_CLOSE)) {} BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); - int len = BIO_read(bio, output, input.length()); + int len = BIO_read(bio, out, input.length()); BIO_free_all(bio); - return string(output, len); + return string(out, len); }; +#pragma GCC diagnostic pop static string SHA1 (const string &input, const bool &rawbin = false) { return SHA(input, rawbin, ::SHA1, SHA_DIGEST_LENGTH); }; @@ -1262,10 +1287,10 @@ namespace ₿ { static string char16Id() { string id = string(16, ' '); for (auto &it : id) { - const int offset = int64() % (26 + 26 + 10); - if (offset < 26) it = 'a' + offset; - else if (offset < 26 + 26) it = 'A' + offset - 26; - else it = '0' + offset - 26 - 26; + const int offset = int64() % (26 + 26 + 10); + if (offset < 26) it = 'a' + offset; + else if (offset < 26 + 26) it = 'A' + offset - 26; + else it = '0' + offset - 26 - 26; } return id; }; diff --git a/src/lib/Makefile b/src/lib/Makefile index 382ca9f21..39ed1c5e0 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -2,13 +2,13 @@ ERR = *** Unexpected MAKELEVEL = 0. HINT = This Makefile can't be used directly, consider cd ../.. before try again $(if $(subst 0,,${MAKELEVEL}),,$(warning $(ERR));$(error $(HINT))) -V_ZLIB = 1.2.12 -V_SSL = 3.0.0 -V_CURL = 7.80.0 -V_SQL = 3370000 -V_JSON = 3.10.4 +V_ZLIB = 1.3.1 +V_SSL = 3.3.2 +V_CURL = 8.10.0 +V_SQL = 3460100 +V_JSON = 3.11.3 V_CATCH = 2.13.7 -V_UV = 1.42.0 +V_UV = 1.48.0 KBUILD := $(abspath ../../build-$(KHOST)) @@ -37,8 +37,8 @@ clean: @rm -vrf $(KBUILD) check: - # zlib | $(V_ZLIB) | $(shell curl -s https://www.zlib.net/ChangeLog.txt | grep "Changes in " | head -n1 | cut -d' ' -f3) - # openssl | $(V_SSL) | $(shell curl -s https://www.openssl.org/news/cl$(shell curl -s https://www.openssl.org/source/ | grep "The latest stable version is " | cut -d' ' -f12 | tr -d '.').txt | grep "Changes between " | head -n1 | cut -d' ' -f4) + # zlib | $(V_ZLIB) | $(shell curl -s https://www.zlib.net/ChangeLog.txt | grep "Changes in " | head -n1 | cut -d' ' -f3) + # openssl | $(V_SSL) | $(shell curl -s https://api.github.com/repos/openssl/openssl/releases | grep "tag_name" | grep $(shell curl -s https://openssl-library.org/source/ | grep "The latest stable version is " | cut -d' ' -f8) | head -n1 | cut -d'o' -f2 | cut -d'-' -f2 | cut -d'"' -f1) # curl | $(V_CURL) | $(shell curl -s https://curl.se/changes.html | grep "Fixed in " | head -n1 | cut -d' ' -f4) # sqlite | $(V_SQL) | $(shell curl -s https://www.sqlite.org/download.html | grep "sqlite-amalgamation-" | head -n1 | cut -d'-' -f3 | cut -d'.' -f1) # json | $(V_JSON) | $(shell curl -s https://api.github.com/repos/nlohmann/json/releases | grep "tag_name" | head -n1 | cut -d'v' -f2 | cut -d'"' -f1) @@ -54,11 +54,12 @@ zlib: ./configure --static --prefix=$(KBUILD) && make all install) ) openssl: - test -d $(KBUILD)/var/openssl-$(V_SSL) || ( \ - curl -L https://www.openssl.org/source/openssl-$(V_SSL).tar.gz | tar xz -C $(KBUILD)/var \ - && cd $(KBUILD)/var/openssl-$(V_SSL) && CC=gcc ./Configure no-asm --openssldir=$(KBUILD) \ - $(if $(findstring mingw32,$(CHOST)),mingw64 -static --libdir=lib,gcc) \ - --prefix=$(KBUILD) --cross-compile-prefix=$(CHOST)- && make install_dev ) + test -d $(KBUILD)/var/openssl-$(V_SSL) || ( \ + curl -L https://github.com/openssl/openssl/releases/download/openssl-$(V_SSL)/openssl-$(V_SSL).tar.gz \ + | tar xz -C $(KBUILD)/var && cd $(KBUILD)/var/openssl-$(V_SSL) \ + && CC=gcc ./Configure no-asm --openssldir=$(KBUILD) \ + $(if $(findstring mingw32,$(CHOST)),mingw64 -static --libdir=lib,gcc) \ + --prefix=$(KBUILD) --cross-compile-prefix=$(CHOST)- && make install_dev ) curl: test -d $(KBUILD)/var/curl-$(V_CURL) || ( \ @@ -76,7 +77,7 @@ curl: sqlite: test -d $(KBUILD)/var/sqlite-autoconf-$(V_SQL) || ( \ - curl -L https://sqlite.org/2021/sqlite-autoconf-$(V_SQL).tar.gz | tar xz -C $(KBUILD)/var \ + curl -L https://sqlite.org/2024/sqlite-autoconf-$(V_SQL).tar.gz | tar xz -C $(KBUILD)/var \ && cd $(KBUILD)/var/sqlite-autoconf-$(V_SQL) && ./configure --prefix=$(KBUILD) \ --host=$(CHOST) --enable-static --disable-dynamic-extensions --disable-shared \ --enable-threadsafe && make install-libLTLIBRARIES install-includeHEADERS ) @@ -85,9 +86,7 @@ json: test -f $(KBUILD)/include/json.h || (mkdir -p $(KBUILD)/include \ && curl -L https://github.com/nlohmann/json/releases/download/v$(V_JSON)/json.hpp \ -o $(KBUILD)/include/json.h && \ - sed -i '$$iusing namespace nlohmann;' $(KBUILD)/include/json.h \ - $(if $(findstring mingw32,$(CHOST)), \ - && sed -i "s/\(#include \)/\/\/\1/" $(KBUILD)/include/json.h) ) + sed -i '$$iusing namespace nlohmann;' $(KBUILD)/include/json.h ) catch: test -f $(KBUILD)/include/catch.h || (mkdir -p $(KBUILD)/include \ @@ -99,7 +98,9 @@ uv: test -d $(KBUILD)/var/libuv-$(V_UV) || ( \ curl -L https://github.com/libuv/libuv/archive/v$(V_UV).tar.gz | tar xz -C $(KBUILD)/var \ && cd $(KBUILD)/var/libuv-$(V_UV) && sh autogen.sh && CC=$(CHOST)-gcc ./configure --host=$(CHOST) \ - --prefix=$(KBUILD) --disable-shared --enable-static && make all install) ) + --prefix=$(KBUILD) --disable-shared --enable-static && make all install \ + $(if $(findstring mingw32,$(CHOST)), \ + && sed -i "s/\(#define SIGQUIT\)/\/\/\1/" $(KBUILD)/include/uv/win.h)) ) pvs: ifndef V_PVS