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.
+
+
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 $*.scss),$(SASS) $(realpath $(x)):$(KASSETS)/$@/$(notdir $(basename $(x))).min.$@;)
cp -R $(NODE_PATH)/beacons $(KASSETS)/font
cat $(NODE_PATH)/@ag-grid-community/all-modules/dist/styles/ag-grid.$@ $(NODE_PATH)/@ag-grid-community/all-modules/dist/styles/ag-theme-bootstrap.min.$@ $(KASSETS)/font/beacons.$@ >> $(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