Repository: DeviaVir/zenbot Branch: unstable Commit: 52872fb4b5f9 Files: 294 Total size: 4.7 MB Directory structure: gitextract_l1jpdydj/ ├── .dockerignore ├── .editorconfig ├── .env-sample ├── .eslintignore ├── .eslintrc ├── .github/ │ └── stale.yml ├── .gitignore ├── .jsbeautifyrc ├── .snyk ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── ISSUE_TEMPLATE.md ├── LICENSE ├── Makefile ├── README.md ├── boot.js ├── commands/ │ ├── backfill/ │ │ ├── backfill.consume.function.js │ │ ├── backfill.function.js │ │ ├── backfill.process.function.js │ │ └── backfill.update-screen.function.js │ ├── backfill.js │ ├── balance.js │ ├── buy.js │ ├── list-selectors.js │ ├── list-strategies.js │ ├── new_backfill.js │ ├── sell.js │ ├── sim.js │ └── trade.js ├── conf-sample.js ├── docker-compose-traefik.yml ├── docker-compose-windows.yml ├── docker-compose.yml ├── docs/ │ ├── FAQ.md │ ├── README.md │ ├── developers.md │ ├── exchanges/ │ │ ├── bitstamp.md │ │ ├── gdax.md │ │ ├── kraken.md │ │ └── readme.md │ ├── installation/ │ │ ├── README.md │ │ ├── debian-ubuntu.md │ │ ├── docker.md │ │ ├── raspberrypi.md │ │ └── requirements.md │ ├── notifiers/ │ │ └── README.md │ ├── scripts/ │ │ ├── genetic_backtester.md │ │ └── readme.md │ └── strategies/ │ ├── howto_create_strategy.md │ ├── list-strategies.md │ ├── macd.md │ ├── noop.md │ ├── rsi.md │ ├── sar.md │ ├── speed.md │ ├── trend_ema.md │ └── tweaking.md ├── extensions/ │ ├── README.md │ ├── exchanges/ │ │ ├── _stub/ │ │ │ ├── _codemap.js │ │ │ ├── exchange.js │ │ │ └── products.json │ │ ├── binance/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── binanceus/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── bitfinex/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── bitstamp/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── bittrex/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── cexio/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── gdax/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ ├── test.js │ │ │ └── update-products.sh │ │ ├── gemini/ │ │ │ ├── .snyk │ │ │ ├── exchange.js │ │ │ ├── package.json │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── hitbtc/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── kraken/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── poloniex/ │ │ │ ├── exchange.js │ │ │ ├── products.json │ │ │ └── update-products.sh │ │ ├── sim/ │ │ │ └── exchange.js │ │ └── therock/ │ │ ├── exchange.js │ │ ├── products.json │ │ └── update-products.sh │ ├── notifiers/ │ │ ├── adamant.js │ │ ├── discord.js │ │ ├── ifttt.js │ │ ├── prowl.js │ │ ├── pushbullet.js │ │ ├── pushover.js │ │ ├── slack.js │ │ ├── telegram.js │ │ ├── textbelt.js │ │ └── xmpp.js │ ├── output/ │ │ ├── _codemap.js │ │ └── api.js │ └── strategies/ │ ├── bollinger/ │ │ └── strategy.js │ ├── cci_srsi/ │ │ └── strategy.js │ ├── crossover_vwap/ │ │ ├── example_sims/ │ │ │ ├── index.html │ │ │ ├── main.css │ │ │ ├── vwapmax0.html │ │ │ ├── vwapmax10.html │ │ │ ├── vwapmax100.html │ │ │ ├── vwapmax1000.html │ │ │ ├── vwapmax10000.html │ │ │ ├── vwapmax20000.html │ │ │ ├── vwapmax500.html │ │ │ └── vwapmax5000.html │ │ └── strategy.js │ ├── dema/ │ │ └── strategy.js │ ├── ehlers_ft/ │ │ └── strategy.js │ ├── ehlers_mama/ │ │ ├── README.md │ │ └── strategy.js │ ├── ehlers_trend/ │ │ ├── README.md │ │ └── strategy.js │ ├── ichimoku/ │ │ └── strategy.js │ ├── ichimoku_score/ │ │ ├── README.md │ │ └── strategy.js │ ├── kc/ │ │ └── strategy.js │ ├── macd/ │ │ └── strategy.js │ ├── momentum/ │ │ └── strategy.js │ ├── multi/ │ │ └── strategy.js │ ├── neural/ │ │ ├── README.md │ │ └── strategy.js │ ├── noop/ │ │ └── strategy.js │ ├── pivot/ │ │ └── strategy.js │ ├── renko/ │ │ └── strategy.js │ ├── rsi/ │ │ └── strategy.js │ ├── sar/ │ │ └── strategy.js │ ├── speed/ │ │ └── strategy.js │ ├── srsi_macd/ │ │ └── strategy.js │ ├── stddev/ │ │ └── strategy.js │ ├── ta_ema/ │ │ └── strategy.js │ ├── ta_macd/ │ │ └── strategy.js │ ├── ta_macd_ext/ │ │ └── strategy.js │ ├── ta_ppo/ │ │ └── strategy.js │ ├── ta_srsi_bollinger/ │ │ └── strategy.js │ ├── ta_stoch_bollinger/ │ │ └── strategy.js │ ├── ta_trix/ │ │ └── strategy.js │ ├── ta_ultosc/ │ │ └── strategy.js │ ├── ti_bollinger/ │ │ └── strategy.js │ ├── ti_hma/ │ │ └── strategy.js │ ├── ti_stoch/ │ │ └── strategy.js │ ├── ti_stoch_bollinger/ │ │ └── strategy.js │ ├── trend_bollinger/ │ │ └── strategy.js │ ├── trend_ema/ │ │ └── strategy.js │ ├── trendline/ │ │ ├── README.md │ │ └── strategy.js │ ├── trust_distrust/ │ │ └── strategy.js │ ├── vpt/ │ │ └── strategy.js │ └── wavetrend/ │ └── strategy.js ├── lib/ │ ├── _data-structures/ │ │ └── Queue.js │ ├── adx.js │ ├── backtester.js │ ├── bollinger.js │ ├── cci.js │ ├── cmf.js │ ├── debug.js │ ├── ema.js │ ├── engine.js │ ├── format.js │ ├── heikinAshi.js │ ├── helpers.js │ ├── highest.js │ ├── kc.js │ ├── lowest.js │ ├── lrc.js │ ├── momentum.js │ ├── normalize-selector.js │ ├── notify.js │ ├── objectify-selector.js │ ├── output.js │ ├── phenotype.js │ ├── rsi.js │ ├── sar.js │ ├── services/ │ │ ├── collection-service.js │ │ ├── consume-and-process-service.js │ │ ├── exchange-service.js │ │ ├── resume-marker-service.js │ │ └── trades-service.js │ ├── slow_stochastic.js │ ├── sma.js │ ├── srsi.js │ ├── stddev.js │ ├── ta_bollinger.js │ ├── ta_ema.js │ ├── ta_macd.js │ ├── ta_macd_ext.js │ ├── ta_ppo.js │ ├── ta_stoch.js │ ├── ta_stochrsi.js │ ├── ta_trix.js │ ├── ta_ultosc.js │ ├── ta_volume.js │ ├── ta_willr.js │ ├── tcf.js │ ├── ti_bollinger.js │ ├── ti_hma.js │ ├── ti_macd.js │ ├── ti_rsi.js │ ├── ti_stoch.js │ ├── ti_stochrsi.js │ ├── vma.js │ ├── vwap.js │ └── wto.js ├── models/ │ └── README.md ├── package.json ├── post_install.js ├── scripts/ │ ├── auto_backtester/ │ │ ├── .snyk │ │ ├── backtester.js │ │ ├── backtester_trust_distrust.js │ │ └── package.json │ ├── cron.sh │ ├── genetic_algo/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── conda_environment.yaml │ │ ├── conf.py │ │ ├── constants.py │ │ ├── docker-compose.yml │ │ ├── evaluation.py │ │ ├── evolution/ │ │ │ ├── __init__.py │ │ │ ├── core.py │ │ │ ├── individual_base.py │ │ │ ├── selection.py │ │ │ └── utils.py │ │ ├── fabfile.py │ │ ├── halloffame.py │ │ ├── main.py │ │ ├── objective_function.py │ │ ├── parsing.py │ │ ├── requirements.txt │ │ ├── tests/ │ │ │ ├── __init__.py │ │ │ ├── test_evaluation.py │ │ │ ├── test_evolution.py │ │ │ ├── test_integration.py │ │ │ └── test_objective.py │ │ ├── utils.py │ │ └── zendividual.py │ └── genetic_backtester/ │ ├── darwin.js │ └── package.json ├── stats/ │ ├── index.html │ └── readme.md ├── templates/ │ ├── dashboard.ejs │ └── dashboard_assets/ │ ├── css/ │ │ ├── animate.css │ │ ├── colors/ │ │ │ └── default.css │ │ ├── spinners.css │ │ └── style.css │ ├── js/ │ │ ├── custom.js │ │ └── jquery.slimscroll.js │ └── manifest.json ├── test/ │ ├── _mocks/ │ │ ├── collectionService.mock.factory.js │ │ ├── consumeAndProcessService.mock.factory.js │ │ ├── exchangeService.mock.factory.js │ │ ├── resumeMarkerService.mock.factory.js │ │ └── tradeService.mock.factory.js │ ├── _specs/ │ │ ├── commands/ │ │ │ └── backfill/ │ │ │ ├── backfill.consume.function.test.js │ │ │ ├── backfill.function.test.js │ │ │ └── backfill.process.function.test.js │ │ └── lib/ │ │ └── services/ │ │ ├── collections-service.test.js │ │ ├── consume-and-process-service.test.js │ │ ├── exchange-service.test.js │ │ ├── resume-marker-service.test.js │ │ └── trades-service.test.js │ └── lib/ │ ├── engine.test.js │ ├── format.test.js │ ├── rsi.test.js │ └── srsi.test.js ├── update.bat ├── update.sh ├── webpack-src/ │ └── js/ │ ├── app.js │ └── echarts.js ├── webpack.config.js ├── zenbot.bat ├── zenbot.js └── zenbot.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ node_modules data database simulations/* docs docker-compose* Dockerfile conf.js *.md .gitignore .dockerignore .github/ ================================================ FILE: .editorconfig ================================================ root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true [*.{js,json}] charset = utf-8 indent_style = space [*.{js,yml}] indent_size = 2 [*.{json,sh}] indent_size = 4 [Makefile] indent_style = tab [{package.json,.travis.yml}] indent_style = space indent_size = 2 ================================================ FILE: .env-sample ================================================ BASIC_AUTH_ZEN=ommm:$apr1$1n0zqO2y$A2ueB9zMWZTYTtfckFhql1 TRAEFIK_HOST_ZEN=myhost.com BASIC_AUTH_DB=ommm:$apr1$1n0zqO2y$A2ueB9zMWZTYTtfckFhql1 TRAEFIK_HOST_DB=db.myhost.com TRAEFIK_NETWORK_NAME=traefik-proxy ================================================ FILE: .eslintignore ================================================ scripts/auto_backtester/node_modules/* scripts/genetic_backtester/node_modules/* scripts/genetic_algo/node_modules/* dist templates/dashboard_assets/js/* ================================================ FILE: .eslintrc ================================================ { "env": { "es6": true, "node": true, "jasmine": true, "browser": true }, "extends": "eslint:recommended", "rules": { "no-console": 0, "indent": [ "error", 2 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "never" ] }, "parserOptions": { "sourceType": "module", "ecmaVersion": "2017", "ecmaFeatures": { "experimentalObjectRestSpread": true } } } ================================================ FILE: .github/stale.yml ================================================ # Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: - enhancement - bug - Sticky # Label to use when marking an issue as stale staleLabel: wontfix # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false ================================================ FILE: .gitignore ================================================ .DS_Store .env *.tar.gz *.log.* t.js node_modules npm-debug.log db.json dump conf/secret.json github.pub github config.js config.patch data/* conf.js conf-* conf_* !conf-sample.js sim_result* trade_result* paper_result* *_test backtesting_* generation_data_* simulations/* models/**/*.json models/**/*.html *.pyc *.swp temp.html logs .sync dist/* .idea *.iml simulations/sim_*.json gen.*.bat gen.*.sh .env scripts/auto_backtester/backtesting_*.csv database/* .vscode/ ================================================ FILE: .jsbeautifyrc ================================================ { "indent_size": 2, "js": { "preserve-newlines": true } } ================================================ FILE: .snyk ================================================ # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.16.0 ignore: {} # patches apply the minimum changes required to fix a vulnerability patch: SNYK-JS-LODASH-450202: - adamant-api > bitcore-mnemonic > bitcore-lib > lodash: patched: '2020-03-25T09:47:35.751Z' SNYK-JS-LODASH-567746: - adamant-api > bitcore-mnemonic > bitcore-lib > lodash: patched: '2020-05-01T07:02:24.711Z' - lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > lodash': patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > lodash: patched: '2020-05-01T07:02:24.711Z' - gemini-api > lodash: patched: '2020-05-01T07:02:24.711Z' - node-sass > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helper-module-transforms > lodash': patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > lodash: patched: '2020-05-01T07:02:24.711Z' - extract-text-webpack-plugin > async > lodash: patched: '2020-05-01T07:02:24.711Z' - node-sass > sass-graph > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/ruby-semver > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > inquirer > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-config > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-mvn-plugin > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-nodejs-lockfile-parser > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-nuget-plugin > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helpers > @babel/traverse > lodash': patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > request-promise > request-promise-core > lodash: patched: '2020-05-01T07:02:24.711Z' - node-telegram-bot-api > request-promise > request-promise-core > lodash: patched: '2020-05-01T07:02:24.711Z' - pushbullet > request-promise-native > request-promise-core > lodash: patched: '2020-05-01T07:02:24.711Z' - node-sass > gaze > globule > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/dep-graph > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-go-plugin > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-nodejs-lockfile-parser > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-mvn-plugin > @snyk/java-call-graph-builder > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-nuget-plugin > dotnet-deps-parser > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > snyk-php-plugin > @snyk/composer-lockfile-parser > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helper-module-transforms > @babel/helper-replace-supers > @babel/traverse > lodash': patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > request-promise > request-promise-core > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/ruby-semver > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helper-module-transforms > @babel/helper-replace-supers > @babel/traverse > @babel/generator > lodash': patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/dep-graph > graphlib > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helper-module-transforms > @babel/helper-replace-supers > @babel/traverse > @babel/helper-split-export-declaration > @babel/types > lodash': patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - '@babel/core > @babel/helper-module-transforms > @babel/helper-replace-supers > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash': patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-duplicate-keys > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-shorthand-properties > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-sticky-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-unicode-regex > babel-helper-regex > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-regenerator > regenerator-transform > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-block-scoping > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-computed-properties > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-systemjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-helper-optimise-call-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-parameters > babel-helper-call-delegate > babel-helper-hoist-variables > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-helper-get-function-arity > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-function-name > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-object-super > babel-helper-replace-supers > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-ws1 > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-exponentiation-operator > babel-helper-builder-binary-assignment-operator-visitor > babel-helper-explode-assignable-expression > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-plugin-transform-strict-mode > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-async-to-generator > babel-helper-remap-async-to-generator > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-classes > babel-helper-define-map > babel-helper-function-name > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-api-node-util > babel-preset-env > babel-plugin-transform-es2015-modules-umd > babel-plugin-transform-es2015-modules-amd > babel-plugin-transform-es2015-modules-commonjs > babel-template > babel-traverse > babel-types > lodash: patched: '2020-05-01T07:02:24.711Z' - bitfinex-api-node > bfx-api-node-models > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > blessed-contrib > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/cli > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > create-index > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-block-scoping > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/cli > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-traverse > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > create-index > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-unicode-regex > @babel/helper-regex > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-block-scoping > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-traverse > babel-types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-traverse > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-modules-umd > @babel/helper-module-transforms > @babel/helper-simple-access > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-unicode-regex > @babel/helper-regex > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > babel-eslint > babel-traverse > babel-types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/generator > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-modules-umd > @babel/helper-module-transforms > @babel/helper-simple-access > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/helper-function-name > @babel/template > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/generator > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/helper-function-name > @babel/template > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-es2015 > @babel/plugin-transform-parameters > @babel/helper-call-delegate > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-models > bfx-hf-util > @babel/preset-env > @babel/plugin-transform-exponentiation-operator > @babel/helper-builder-binary-assignment-operator-visitor > @babel/helper-explode-assignable-expression > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash: patched: '2020-07-06T09:32:09.747Z' - bitfinex-api-node > bfx-api-node-rest > bfx-api-node-models > bfx-hf-util > @babel/preset-env > @babel/plugin-transform-exponentiation-operator > @babel/helper-builder-binary-assignment-operator-visitor > @babel/helper-explode-assignable-expression > @babel/traverse > @babel/helper-function-name > @babel/template > @babel/types > lodash: patched: '2020-07-06T09:32:09.747Z' ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - '10' - '11' before_install: - npm install -g node-gyp - if [ "$TRAVIS_NODE_VERSION" = "10" ]; then npm install -g greenkeeper-lockfile@1; fi script: - npm run lint - npm test after_success: - if [ "$TRAVIS_NODE_VERSION" = "10" ]; then greenkeeper-lockfile-update; fi after_script: - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then /bin/sh scripts/cron.sh; fi - if [ "$TRAVIS_NODE_VERSION" = "10" ]; then greenkeeper-lockfile-upload; fi env: global: secure: X5ZcoLrEavb26c1vY6L6hxmOtUGp07ta9jb0heU/9TkR0PCxBwqh1THHZIUO4qhOURSPXmBmajgMBDYzBgHpjd+5PrtF5mTqcRhXLpAbb9RQ0+H9VvTuwAWca6H7jG8RUS7zcV70u9de0zEmRFTX85iusPoIoqF2cafgsMtq6Gtx8rb+4WZ45Etn589RrOaehG2u1w+MW6vzohWpHY6hc3yqFWsKUfDdahWofdmH1SIpEgckbQ26LuaBMfqHeDPHtHsMfloHhukvmPzobBKJ7PuQWtJ/enuygY9ZjAX7NTgWEG7m5SLvJZ4PuVkc9ea0ZHMVB3L9bR2njbtBf4QnRhti/XyaNgBGqTsce52z3Z+3Hs9/Hktbb2KLJ2Jid3nwhoUmYr5HTRPkkQ54gOgLFMshi4H+vr4s+MMcfHQ6B0kjADenEf2vFcMwLCey/ERh52csqdlJviw9IJRa0YrSXc3krnlOVMPHnaOgKuU/hYyM3uj5CzG4iCmqOJG0sBtlrp+Q+q9kDtpNw+U/xRZzJ6+0XmFNtNLz762VCW6zs/zsaJ6livU6rSUOKyUo5v+5Ay6DOAjDe2NM3R7hymvhlWJh8SCLBJEDZsLbeN1pozDatOXsD2OWJnhHYfQbntekytoXy3fSrgZYuWJ6yL/S6R4Eo73XkoL2Bah8+aAhcEE= ================================================ FILE: CHANGELOG.md ================================================ ## Changelog - [v4.1.0](https://github.com/carlos8f/zenbot/releases/tag/v4.1.0) (Latest) - more indicators - more strategies - more exchanges - too many bug fixes to list here - web UI - Travis - Docker automated builds - Automated tests - [v4.0.5](https://github.com/carlos8f/zenbot/releases/tag/v4.0.5) - handle insufficient funds errors from gdax - new trend_ema defaults adjusted for latest btc movements: 20m period, neutral_rate=0 - include more data in sim output - remove rarely useful trend_ema options - avoid abort in trader on failed getTrades() - v4.0.4 - debugging for polo odd results - sim: simplify and correct makerFee assessment - fix conf path in API credentials errors - fix order total under 0.0001 error on polo - Docker: extend README slightly (thanks [@DeviaVir](https://github.com/deviavir) and [@egorbenko](https://github.com/egorbenko)) - docker-compose: do not expose mongodb by default! (thanks [@DeviaVir](https://github.com/deviavir)) - v4.0.3 - fix for docker mongo host error - link for new Discord chat! - fix polo crash on getOrder weird result - fix oversold_rsi trigger while in preroll - fix polo "not enough..." errors - fancy colors for price report - display product id in report - fix poloniex backfill batches too big, mongo timeouts - fix cursorTo() crash on some node installs - memDump for debugging order failures - fix column spacing on progress report - v4.0.2 - minor overhaul to trend_ema strat - added whipsaw filtering via std. deviation (`--neutral_rate=auto`) - trim preroll of sim result graph - v4.0.1 - Added .dockerignore (thanks [@sulphur](https://github.com/sulphur)) - fix crashing on mongo timeout during backfill - fix gaps in poloniex backfill - default backfill days 90 -> 14 ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at carlos@s8f.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: Dockerfile ================================================ FROM node:10 as builder ADD . /app WORKDIR /app RUN npm install -g node-gyp RUN npm install --unsafe FROM node:10-alpine COPY zenbot.sh /usr/local/bin/zenbot WORKDIR /app RUN chown -R node:node /app COPY --chown=node . /app COPY --chown=node --from=builder /usr/local/lib/node_modules/ /usr/local/lib/node_modules/ COPY --chown=node --from=builder /app/node_modules /app/node_modules/ USER node ENV NODE_ENV production ENTRYPOINT ["/usr/local/bin/zenbot"] CMD ["trade","--paper"] ================================================ FILE: ISSUE_TEMPLATE.md ================================================ KINDLY READ AND ACT ON THE BELOW INFORMATION BEFORE FILING YOUR ISSUE! Please go to our Zenbot subreddit for questions, help and support: [https://www.reddit.com/r/zenbot/](https://www.reddit.com/r/zenbot/) If you open a GitHub issue, here is our policy: 1. It must be a bug or a feature request. 2. The form below must be filled out. **Here's why we have that policy**: Zenbot developers respond to issues. We want to focus on work that benefits the whole community, e.g., fixing bugs and adding features. Support only helps individuals and rarely leads to bugfixes or useful enhancements. GitHub also notifies hundreds of people when issues are filed. We want them to see you communicating an interesting problem, rather than being redirected to Reddit. ------------------------ Remove everything above before creating your issue. ------------------------ ### System information - **Have I written custom code (as opposed to using zenbot vanilla)**: - **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: - **Zenbot version** (commit ref, or version): - **Zenbot branch**: - **NodeJS version**: - **Python version (when using a python script)**: - **Exact command to reproduce (include everything)**: - **Did I make any changes to conf-sample.js?**: ### Describe the problem Describe the problem clearly here. Be sure to convey here why it's a bug in Zenbot or a feature request. ### Source code / Error logs Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 Carlos Rodriguez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ # Check if this is Windows ifneq (,$(findstring WINDOWS,$(PATH))) WINDOWS := True endif # Set shell to cmd on windows ifdef WINDOWS SHELL := C:/Windows/System32/cmd.exe endif # Don't use sudo on windows SUDO := "sudo" ifdef WINDOWS SUDO := endif # set home dir to user's home on windows running MINGW ifdef MSYSTEM HOME := $(subst \,/,$(HOME)) endif # Get the root dir of this file ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) # Define the full path to this file THIS_FILE := $(lastword $(MAKEFILE_LIST)) # Set docker-compose file selector for windows ifneq (,$(findstring WINDOWS,$(PATH))) DC_CONFIG=$(ROOT_DIR)/docker-compose-windows.yml else DC_CONFIG=$(ROOT_DIR)/docker-compose.yml endif # Find or create a home for sensitive environment variables # Check my secret place CREDS=$(HOME)/.bash/.credentials ifneq ("$(wildcard $(CREDS))","") CREDENTIALS := $(CREDS) else # Check a normal place CREDS=$(HOME)/.credentials ifneq ("$(wildcard $(CREDS))","") CREDENTIALS := $(CREDS) else $(info $(shell "mkdir" $(CREDS))) endif endif # To use arguments with make execute: make -- ARGS = $(filter-out $@,$(MAKECMDGOALS)) MAKEFLAGS += --silent list: sh -c "echo; $(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | grep -v 'Makefile'| sort" ############################# # ZENBOT ############################# list-strategies: docker-compose exec server zenbot list-strategies $(ARGS) list-selectors: docker-compose exec server zenbot list-selectors $(ARGS) backfill: docker-compose exec server zenbot backfill $(ARGS) sim: docker-compose exec server zenbot sim $(ARGS) trade: docker-compose exec server zenbot trade $(ARGS) paper: docker-compose exec server zenbot trade --paper $(ARGS) balance: docker-compose exec server zenbot balance $(ARGS) buy: docker-compose exec server zenbot buy $(ARGS) sell: docker-compose exec server zenbot sell $(ARGS) zenbot: docker-compose exec server zenbot $(ARGS) ############################# # Docker machine states ############################# time-sync: docker run --rm --privileged alpine hwclock -s up: $(SUDO) docker-compose --file=$(DC_CONFIG) up start: docker-compose start stop: docker-compose stop state: docker-compose ps rebuild: $(SUDO) docker-compose stop $(SUDO) docker-compose pull $(SUDO) docker-compose rm --force server $(SUDO) docker-compose rm --force mongodb -$(SUDO) docker-compose rm --force adminmongo $(SUDO) docker-compose build --no-cache $(SUDO) docker-compose --file=$(DC_CONFIG) up -d --force-recreate shell: docker-compose exec server /bin/sh shellw: docker exec -it -u root $$(docker-compose ps -q server) /bin/sh logs: docker-compose logs $(ARGS) ############################# # Argument fix workaround ############################# %: @: ================================================ FILE: README.md ================================================ WARNING: project is no longer actively maintained, make sure to update any dependencies if you plan on using this in your project. ![zenbot logo](assets/logo.png) > “To follow the path, look to the master, follow the master, walk with the master, see through the master, become the master.” > – Zen Proverb # Zenbot [![Build/Test Status](https://travis-ci.org/DeviaVir/zenbot.svg?branch=master)](https://travis-ci.org/DeviaVir/zenbot) ## Description Zenbot is a command-line cryptocurrency trading bot using Node.js and MongoDB. It features: - Fully-automated [technical-analysis](https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:introduction_to_technical_indicators_and_oscillators)-based trading approach - Full support for [Binance](https://www.binance.com/), [Bitfinex](https://www.bitfinex.com/), [Bitstamp](https://www.bitstamp.net/), [Bittrex](https://bittrex.com/), [CEX.IO](https://cex.io/), [GDAX](https://gdax.com/), [Gemini](https://gemini.com/), [HitBTC](https://hitbtc.com/), [Kraken](https://www.kraken.com/), [Poloniex](https://poloniex.com/)and [TheRockTrading](https://www.therocktrading.com/), work on further exchange support is ongoing. - Plugin architecture for implementing exchange support, or writing new strategies - Simulator for [backtesting strategies](https://gist.github.com/carlos8f/b09a734cf626ffb9bb3bcb1ca35f3db4) against historical data - "Paper" trading mode, operates on a simulated balance while watching the live market - Configurable sell stops, buy stops, and (trailing) profit stops - Flexible sampling period and trade frequency - averages 1-2 trades/day with 1h period, 15-50/day with 5m period ## Disclaimer - Zenbot is NOT a sure-fire profit machine. Use it AT YOUR OWN RISK. - Crypto-currency is still an experiment, and therefore so is Zenbot. Meaning, both may fail at any time. - Running a bot, and trading in general requires careful study of the risks and parameters involved. A wrong setting can cause you a major loss. - Never leave the bot un-monitored for long periods of time. Zenbot doesn't know when to stop, so be prepared to stop it if too much loss occurs. - Often times the default trade parameters will underperform vs. a buy-hold strategy, so run some simulations and find the optimal parameters for your chosen exchange/pair before going "all-in". ## Documentation The extensive documentation is located at the [docs-folder](docs/). ### Questions First have a look at the [docs](docs/) and there are also [FAQs](docs/FAQ.md) which may answer your questions. If not, please ask (programming) questions related to Zenbot on Reddit ([subreddit zenbot](https://reddit.com/r/zenbot)). ### Community Join the [Zenbot community on Reddit](https://reddit.com/r/zenbot)! ## Donate P.S., some have asked for how to donate to Zenbot development. We accept donations at **Bitcoin addresses** below: ### carlos8f's BTC (original Zenbot author) `187rmNSkSvehgcKpBunre6a5wA5hQQop6W` ### DeviaVir's BTC (current maintainer) `3A5g4GQ2vmjNcnEschCweJJB4umzu66sdY` ![zenbot logo](assets/zenbot_square.png) Thanks! ## Noteworthy forks - [bot18](https://medium.com/@carlos8f_11468/introducing-bot18-the-new-crypto-trading-bot-to-supersede-zenbot-and-unleash-the-zalgo-da8464b41e53) - [magic8bot](https://github.com/notVitaliy/magic8bot) - - - ## License: MIT - Copyright (C) 2018 Carlos Rodriguez - Copyright (C) 2018 Terra Eclipse, Inc. (http://www.terraeclipse.com/) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: boot.js ================================================ var _ = require('lodash') var path = require('path') var minimist = require('minimist') var version = require('./package.json').version var EventEmitter = require('events') module.exports = function (cb) { var zenbot = { version } var args = minimist(process.argv.slice(3)) var conf = {} var config = {} var overrides = {} module.exports.debug = args.debug // 1. load conf overrides file if present if(!_.isUndefined(args.conf)){ try { overrides = require(path.resolve(process.cwd(), args.conf)) } catch (err) { console.error(err + ', failed to load conf overrides file!') } } // 2. load conf.js if present try { conf = require('./conf') } catch (err) { console.error(err + ', falling back to conf-sample') } // 3. Load conf-sample.js and merge var defaults = require('./conf-sample') _.defaultsDeep(config, overrides, conf, defaults) zenbot.conf = config var eventBus = new EventEmitter() zenbot.conf.eventBus = eventBus var authStr = '', authMechanism, connectionString if(zenbot.conf.mongo.username){ authStr = encodeURIComponent(zenbot.conf.mongo.username) if(zenbot.conf.mongo.password) authStr += ':' + encodeURIComponent(zenbot.conf.mongo.password) authStr += '@' // authMechanism could be a conf.js parameter to support more mongodb authentication methods authMechanism = zenbot.conf.mongo.authMechanism || 'DEFAULT' } if (zenbot.conf.mongo.connectionString) { connectionString = zenbot.conf.mongo.connectionString } else { connectionString = 'mongodb://' + authStr + zenbot.conf.mongo.host + ':' + zenbot.conf.mongo.port + '/' + zenbot.conf.mongo.db + '?' + (zenbot.conf.mongo.replicaSet ? '&replicaSet=' + zenbot.conf.mongo.replicaSet : '' ) + (authMechanism ? '&authMechanism=' + authMechanism : '' ) } require('mongodb').MongoClient.connect(connectionString, { useNewUrlParser: true, useUnifiedTopology: true}, function (err, client) { if (err) { console.error('WARNING: MongoDB Connection Error: ', err) console.error('WARNING: without MongoDB some features (such as backfilling/simulation) may be disabled.') console.error('Attempted authentication string: ' + connectionString) cb(null, zenbot) return } var db = client.db(zenbot.conf.mongo.db) _.set(zenbot, 'conf.db.mongo', db) cb(null, zenbot) }) } ================================================ FILE: commands/backfill/backfill.consume.function.js ================================================ /* This module provides a function, used in the backfill process, to consume trades. It is accompanied by another class which processes those trades. In this case, processing means storing in the database. It makes a call to a service to get trades. If trades are returned, it stores them in a queue. Finally, regardless, a status code is returned. Its either cp_process, to process the trades, or cp_exit, exit the consume-and-process flow. */ var tradesService = require('../../lib/services/trades-service') module.exports = function (conf) { var tradesServiceInstance = tradesService(conf) return (mostRecentlyProcessedTradeId, queue, cb) => { tradesServiceInstance.getTrades(mostRecentlyProcessedTradeId).then(function (returnedTrades) { if (returnedTrades.length > 0) { queue.enqueue(returnedTrades.sort((a, b) => { return b.trade_id - a.trade_id }) ) cb(null, 'cp_process', returnedTrades[returnedTrades.length - 1].trade_id) } else { cb(null, 'cp_exit', undefined) } }) } } ================================================ FILE: commands/backfill/backfill.function.js ================================================ var consumeAndProcessService = require('../../lib/services/consume-and-process-service'), backfillConsumeFunction = require('./backfill.consume.function'), backfillProcessFunction = require('./backfill.process.function'), backfillUpdateScreenFunction = require('./backfill.update-screen.function') module.exports = function container (conf) { /** * Backfilling consists of two steps: consuming the trades, and processing (persisting) them. * This function sets up the service that manages that. */ return function (targetTimeInMillis) { var cpService = consumeAndProcessService(conf) cpService.setOnConsumeFunc(backfillConsumeFunction(conf)) cpService.setOnProcessFunc(backfillProcessFunction(conf)) cpService.setAfterOnProcessFunc(backfillUpdateScreenFunction) return new Promise((resolve/*, reject*/) => { cpService.go(targetTimeInMillis).then((finalTrade) => { resolve(finalTrade) }) }, function (err) { console.log('Something bad happened while getting trades :(') console.log(err) }) } } ================================================ FILE: commands/backfill/backfill.process.function.js ================================================ /* Processes the trades.. */ var collectionService = require('../../lib/services/collection-service') module.exports = function (conf) { var collectionServiceInstance = collectionService(conf) return (targetTimeInMillis, queue, getIDofNextTradeToProcessFunc, cb) => { var trades = queue.dequeue() var prev var curr var rtnTrade var index = 0 var moreInThisBatch = true var stopProcessingConditionReached = false do { prev = curr curr = trades[index++] if (curr === undefined) { rtnTrade = prev moreInThisBatch = false } else { if (curr.time > targetTimeInMillis) { let skipToTradeId = getIDofNextTradeToProcessFunc(curr) // if number we can skip to === currtrade if (skipToTradeId === curr.trade_id) { let lastTrade = curr let idx = {i: index} collectionServiceInstance.getTrades().insertOne(curr).then((/*err, doc*/) => { if (idx.i === trades.length) { cb(null, false, lastTrade.trade_id, lastTrade) } }) } else { moreInThisBatch = false cb(null, false, skipToTradeId, curr) } } else { // this is past our time limit... moreInThisBatch = false stopProcessingConditionReached = true rtnTrade = prev || curr } } } while (moreInThisBatch) if (stopProcessingConditionReached) { cb(null, stopProcessingConditionReached, rtnTrade.trade_id, rtnTrade) } } } ================================================ FILE: commands/backfill/backfill.update-screen.function.js ================================================ var Moment = require('moment') module.exports = (trade_id, data) => { if (data !== undefined && typeof process.stdout.clearLine == 'function') { process.stdout.clearLine() process.stdout.write(data.pingCount + ' trades processed so far. The most recently processed trade happened ' + Moment(data.time).fromNow() + '.' ) process.stdout.cursorTo(0) } } ================================================ FILE: commands/backfill.js ================================================ var tb = require('timebucket') , crypto = require('crypto') , objectifySelector = require('../lib/objectify-selector') , collectionService = require('../lib/services/collection-service') , moment = require('moment') module.exports = function (program, conf) { program .command('backfill [selector]') .description('download historical trades for analysis') .option('--conf ', 'path to optional conf overrides file') .option('--debug', 'output detailed debug info') .option('-d, --days ', 'number of days to acquire (default: ' + conf.days + ')', Number, conf.days) .option('--start | ', 'lower bound as unix time in ms or format ("YYYYMMDDhhmm")', Number, -1) .option('--end | ', 'upper bound as unix time in ms or format ("YYYYMMDDhhmm")', Number, -1) .action(function (selector, cmd) { selector = objectifySelector(selector || conf.selector) var exchange = require(`../extensions/exchanges/${selector.exchange_id}/exchange`)(conf) if (!exchange) { console.error('cannot backfill ' + selector.normalized + ': exchange not implemented') process.exit(1) } var collectionServiceInstance = collectionService(conf) var tradesCollection = collectionServiceInstance.getTrades() var resume_markers = collectionServiceInstance.getResumeMarkers() var marker = { id: crypto.randomBytes(4).toString('hex'), selector: selector.normalized, from: null, to: null, oldest_time: null, newest_time: null } marker._id = marker.id var trade_counter = 0 var day_trade_counter = 0 var get_trade_retry_count = 0 var days_left = cmd.days + 1 var target_time, start_time var mode = exchange.historyScan var last_batch_id, last_batch_opts var offset = exchange.offset var markers, trades if (!mode) { console.error('cannot backfill ' + selector.normalized + ': exchange does not offer historical data') process.exit(0) } if (mode === 'backward') { target_time = new Date().getTime() - (86400000 * cmd.days) } else { if(cmd.start >= 0 && cmd.end >= 0){ if (moment(cmd.start, 'YYYYMMDDhhmm').isValid() && moment(cmd.end, 'YYYYMMDDhhmm').isValid()) { start_time = moment(cmd.start, 'YYYYMMDDhhmm').valueOf() target_time = moment(cmd.end, 'YYYYMMDDhhmm').valueOf() } else { start_time = cmd.start target_time = cmd.end } } else { target_time = new Date().getTime() start_time = new Date().getTime() - (86400000 * cmd.days) } } resume_markers.find({selector: selector.normalized}).toArray(function (err, results) { if (err) throw err markers = results.sort(function (a, b) { if (mode === 'backward') { if (a.to > b.to) return -1 if (a.to < b.to) return 1 } else { if (a.from < b.from) return -1 if (a.from > b.from) return 1 } return 0 }) getNext() }) function getNext () { var opts = {product_id: selector.product_id} if (mode === 'backward') { opts.to = marker.from } else { if (marker.to) opts.from = marker.to + 1 else opts.from = exchange.getCursor(start_time) } if (offset) { opts.offset = offset } last_batch_opts = opts exchange.getTrades(opts, function (err, results) { trades = results if (err) { console.error('err backfilling selector: ' + selector.normalized) console.error(err) if (err.code === 'ETIMEDOUT' || err.code === 'ENOTFOUND' || err.code === 'ECONNRESET') { console.error('retrying...') setImmediate(getNext) return } console.error('aborting!') process.exit(1) } if (mode !== 'backward' && !trades.length) { if (trade_counter) { console.log('\ndownload complete!\n') process.exit(0) } else { if (get_trade_retry_count < 5) { console.error('\ngetTrades() returned no trades, retrying with smaller interval.') get_trade_retry_count++ start_time += (target_time - start_time)*0.4 setImmediate(getNext) return } else { console.error('\ngetTrades() returned no trades, --start may be too remotely in the past.') process.exit(1) } } } else if (!trades.length) { console.log('\ngetTrades() returned no trades, we may have exhausted the historical data range.') process.exit(0) } trades.sort(function (a, b) { if (mode === 'backward') { if (a.time > b.time) return -1 if (a.time < b.time) return 1 } else { if (a.time < b.time) return -1 if (a.time > b.time) return 1 } return 0 }) if (last_batch_id && last_batch_id === trades[0].trade_id) { console.error('\nerror: getTrades() returned duplicate results') console.error(opts) console.error(last_batch_opts) process.exit(0) } last_batch_id = trades[0].trade_id runTasks(trades) }) } function runTasks (trades) { Promise.all(trades.map((trade)=>saveTrade(trade))).then(function(/*results*/){ var oldest_time = marker.oldest_time var newest_time = marker.newest_time markers.forEach(function (other_marker) { // for backward scan, if the oldest_time is within another marker's range, skip to the other marker's start point. // for forward scan, if the newest_time is within another marker's range, skip to the other marker's end point. if (mode === 'backward' && marker.id !== other_marker.id && marker.from <= other_marker.to && marker.from > other_marker.from) { marker.from = other_marker.from marker.oldest_time = other_marker.oldest_time } else if (mode !== 'backward' && marker.id !== other_marker.id && marker.to >= other_marker.from && marker.to < other_marker.to) { marker.to = other_marker.to marker.newest_time = other_marker.newest_time } }) var diff if (oldest_time !== marker.oldest_time) { diff = tb(oldest_time - marker.oldest_time).resize('1h').value console.log('\nskipping ' + diff + ' hrs of previously collected data') } else if (newest_time !== marker.newest_time) { diff = tb(marker.newest_time - newest_time).resize('1h').value console.log('\nskipping ' + diff + ' hrs of previously collected data') } resume_markers.replaceOne({_id: marker.id}, marker, {upsert: true}) .then(setupNext) .catch(function(err){ if (err) throw err }) }).catch(function(err){ if (err) { console.error(err) console.error('retrying...') return setTimeout(runTasks, 10000, trades) } }) } function setupNext() { trade_counter += trades.length day_trade_counter += trades.length var current_days_left = 1 + (mode === 'backward' ? tb(marker.oldest_time - target_time).resize('1d').value : tb(target_time - marker.newest_time).resize('1d').value) if (current_days_left >= 0 && current_days_left != days_left) { console.log('\n' + selector.normalized, 'saved', day_trade_counter, 'trades', current_days_left, 'days left') day_trade_counter = 0 days_left = current_days_left } else { process.stdout.write('.') } if (mode === 'backward' && marker.oldest_time <= target_time) { console.log('\ndownload complete!\n') process.exit(0) } else if(cmd.start >= 0 && cmd.end >= 0 && target_time <= marker.newest_time){ console.log('\ndownload of span ('+cmd.start+' - '+cmd.end+') complete!\n') process.exit(0) } if (exchange.backfillRateLimit) { setTimeout(getNext, exchange.backfillRateLimit) } else { setImmediate(getNext) } } function saveTrade (trade) { trade.id = selector.normalized + '-' + String(trade.trade_id) trade._id = trade.id trade.selector = selector.normalized var cursor = exchange.getCursor(trade) if (mode === 'backward') { if (!marker.to) { marker.to = cursor marker.oldest_time = trade.time marker.newest_time = trade.time } marker.from = marker.from ? Math.min(marker.from, cursor) : cursor marker.oldest_time = Math.min(marker.oldest_time, trade.time) } else { if (!marker.from) { marker.from = cursor marker.oldest_time = trade.time marker.newest_time = trade.time } marker.to = marker.to ? Math.max(marker.to, cursor) : cursor marker.newest_time = Math.max(marker.newest_time, trade.time) } return tradesCollection.replaceOne({_id: trade.id}, trade, {upsert: true}) } }) } ================================================ FILE: commands/balance.js ================================================ var minimist = require('minimist') , n = require('numbro') // eslint-disable-next-line no-unused-vars , colors = require('colors') , moment = require('moment') , exchangeService = require('../lib/services/exchange-service') , { formatCurrency } = require('../lib/format') module.exports = function (program, conf) { program .command('balance [selector]') .allowUnknownOption() .description('get asset and currency balance from the exchange') //.option('--all', 'output all balances') .option('-c, --calculate_currency ', 'show the full balance in another currency') .option('--debug', 'output detailed debug info') .action(function (selector, cmd) { if (selector !== undefined) conf.selector = selector var exchangeServiceInstance = exchangeService(conf) selector = exchangeServiceInstance.getSelector() var s = { options: minimist(process.argv), selector: selector, product_id: selector.product_id, asset: selector.asset, currency: selector.currency } var so = s.options delete so._ Object.keys(conf).forEach(function (k) { if (typeof cmd[k] !== 'undefined') { so[k] = cmd[k] } }) so.selector = s.selector so.debug = cmd.debug so.mode = 'live' function balance () { var exchange = exchangeServiceInstance.getExchange() if (exchange === undefined) { console.error('\nSorry, couldn\'t find an exchange from selector [' + conf.selector + '].') process.exit(1) } exchange.getBalance(s, function (err, balance) { if (err) throw err exchange.getQuote(s, function (err, quote) { if (err) throw err var bal = moment().format('YYYY-MM-DD HH:mm:ss').grey + ' ' + formatCurrency(quote.ask, s.currency, true, true, false) + ' ' + (s.product_id).grey + '\n' bal += moment().format('YYYY-MM-DD HH:mm:ss').grey + ' Asset: '.grey + n(balance.asset).format('0.00000000').white + ' Available: '.grey + n(balance.asset).subtract(balance.asset_hold).value().toString().yellow + '\n' bal += moment().format('YYYY-MM-DD HH:mm:ss').grey + ' Asset Value: '.grey + n(balance.asset).multiply(quote.ask).value().toString().white + '\n' bal += moment().format('YYYY-MM-DD HH:mm:ss').grey + ' Currency: '.grey + n(balance.currency).format('0.00000000').white + ' Available: '.grey + n(balance.currency).subtract(balance.currency_hold).value().toString().yellow + '\n' bal += moment().format('YYYY-MM-DD HH:mm:ss').grey + ' Total: '.grey + n(balance.asset).multiply(quote.ask).add(balance.currency).value().toString().white console.log(bal) if (so.calculate_currency) { exchange.getQuote({'product_id': s.asset + '-' + so.calculate_currency}, function (err, asset_quote) { if (err) throw err exchange.getQuote({'product_id': s.currency + '-' + so.calculate_currency}, function (err, currency_quote) { if (err) throw err var asset_total = balance.asset * asset_quote.bid var currency_total = balance.currency * currency_quote.bid console.log((so.calculate_currency + ': ').grey + (asset_total + currency_total)) process.exit() }) }) } else { process.exit() } }) }) } balance() }) } ================================================ FILE: commands/buy.js ================================================ var minimist = require('minimist') , n = require('numbro') // eslint-disable-next-line no-unused-vars , colors = require('colors') , objectifySelector = require('../lib/objectify-selector') , engineFactory = require('../lib/engine') , _ = require('lodash') module.exports = function (program, conf) { program .command('buy [selector]') .allowUnknownOption() .description('execute a buy order to the exchange') .option('--pct ', 'buy with this % of currency balance', Number, conf.buy_pct) .option('--order_type ', 'order type to use (maker/taker)', /^(maker|taker)$/i, conf.order_type) .option('--size ', 'buy specific size of currency') .option('--markdown_buy_pct ', '% to mark down buy price', Number, conf.markdown_buy_pct) .option('--order_adjust_time ', 'adjust bid on this interval to keep order competitive', Number, conf.order_adjust_time) .option('--order_poll_time ', 'poll order status on this interval', Number, conf.order_poll_time) .option('--max_slippage_pct ', 'avoid buying at a slippage pct above this float', conf.max_slippage_pct) .option('--debug', 'output detailed debug info') .action(function (selector, cmd) { var s = {options: minimist(process.argv)} var so = s.options delete so._ Object.keys(conf).forEach(function (k) { if (typeof cmd[k] !== 'undefined') { so[k] = cmd[k] } }) so.debug = cmd.debug so.buy_pct = cmd.pct so.selector = objectifySelector(selector || conf.selector) var order_types = ['maker', 'taker'] if (!order_types.includes(so.order_type)) { so.order_type = 'maker' } so.mode = 'live' so.strategy = conf.strategy so.stats = true var engine = engineFactory(s, conf) engine.executeSignal('buy', function (err, order) { if (err) { console.error(err) process.exit(1) } if (!order) { console.error('not enough currency balance to buy!') } process.exit() }, cmd.size) function checkOrder () { if (!_.isEmpty(s.api_order)) { s.exchange.getQuote({product_id: s.product_id}, function (err, quote) { if (err) { throw err } console.log('order status: '.grey + s.api_order.status.green + ', bid: '.grey + n(s.api_order.price).format('0.00000000').yellow + ', '.grey + n(quote.bid).subtract(s.api_order.price).format('0.00000000').red + ' below best bid, '.grey + n(s.api_order.filled_size).divide(s.api_order.size).format('0.0%').green + ' filled'.grey) }) } else { console.log('placing order...') } } setInterval(checkOrder, conf.order_poll_time) }) } ================================================ FILE: commands/list-selectors.js ================================================ // eslint-disable-next-line no-unused-vars var colors = require('colors'), fs = require('fs') module.exports = function (program) { program .command('list-selectors') .description('list available selectors') .action(function (/*cmd*/) { var exchanges = fs.readdirSync('./extensions/exchanges') exchanges.forEach(function(exchange){ if (exchange === 'sim' || exchange === '_stub') return console.log(`${exchange}:`) var products = require(`../extensions/exchanges/${exchange}/products.json`) products.sort(function (a, b) { if (a.asset < b.asset) return -1 if (a.asset > b.asset) return 1 if (a.currency < b.currency) return -1 if (a.currency > b.currency) return 1 return 0 }) products.forEach(function (p) { console.log(' ' + exchange.cyan + '.'.grey + p.asset.green + '-'.grey + p.currency.cyan + (p.label ? (' (' + p.label + ')').grey : '')) }) }) process.exit() }) } ================================================ FILE: commands/list-strategies.js ================================================ var fs = require('fs'), // eslint-disable-next-line no-unused-vars colors = require('colors') module.exports = function (program, conf) { program .command('list-strategies') .description('list available strategies') .action(function (/*cmd*/) { var strategies = fs.readdirSync('./extensions/strategies') strategies.forEach((strategy) => { let strat = require(`../extensions/strategies/${strategy}/strategy`) console.log(strat.name.cyan + (strat.name === conf.strategy ? ' (default)'.grey : '')) if (strat.description) { console.log(' description:'.grey) console.log(' ' + strat.description.grey) } console.log(' options:'.grey) var ctx = { option: function (name, desc, type, def) { console.log((' --' + name).green + '='.grey + ' ' + desc.grey + (typeof def !== 'undefined' ? (' (default: '.grey + def + ')'.grey) : '')) } } strat.getOptions.call(ctx, strat) console.log() }) process.exit() }) } ================================================ FILE: commands/new_backfill.js ================================================ var minimist = require('minimist') , tb = require('timebucket') , exchangeService = require('../lib/services/exchange-service') , objectifySelector = require('../lib/objectify-selector') , backfillFunction = require('./backfill/backfill.function') module.exports = function(program, conf) { program .command('new_backfill [selector]') .description('download historical trades for analysis') .option('-d, --days ', 'number of days to acquire (default: ' + conf.days + ')', Number, conf.days) .action(function (selector, cmd) { var s = {options: minimist(process.argv)} var so = s.options delete so._ Object.keys(conf).forEach(function (k) { if (typeof cmd[k] !== 'undefined') { so[k] = cmd[k] } }) conf.selector = objectifySelector(selector || conf.selector) var exchangeServiceInstance = exchangeService(conf) var exchange = exchangeServiceInstance.getExchange() var exchangeName = exchange.name // TODO: Refactor all exchanges to be in the format of the stub.exchange, so we can use getName() here. if (exchange === undefined) { console.error('\nSorry, couldn\'t find an exchange named [' + exchangeName + '].') process.exit(1) } if (!exchange.historyScan) { console.error('\ncannot backfill ' + exchangeName + ': exchange does not offer historical data') process.exit(1) } if (exchange !== undefined) { var msg = 'Hitting up the exchange \'' + exchangeName + '\' for trades within the past ' + so.days + ' day'; if (so.days > 1) {msg += 's.'} else {msg += '.'} console.log('*************************') console.log(msg) console.log('*************************') console.log('\n\nBackfilling...\n\n') var targetTime = tb(new Date().getTime()).resize('1d').subtract(so.days).toMilliseconds() var backfillFunctionInstance = backfillFunction(conf) backfillFunctionInstance(targetTime).then( (finalTradeId) => { process.stdout.write('\n\n') // TODO: Make this say: "Done. Last processed trade happened on January 37, 2018 10:02 // will have to call the DB, get the trade finalTradeId, and display its time. console.log('final trade id ==> [' + JSON.stringify(finalTradeId) + ']') process.exit(0) }, (err) => { console.log('error. ' + err) } ) } }) } ================================================ FILE: commands/sell.js ================================================ var minimist = require('minimist') , n = require('numbro') // eslint-disable-next-line no-unused-vars , colors = require('colors') , objectifySelector = require('../lib/objectify-selector') , engineFactory = require('../lib/engine') module.exports = function (program, conf) { program .command('sell [selector]') .allowUnknownOption() .description('execute a sell order to the exchange') .option('--pct ', 'sell with this % of currency balance', Number, conf.sell_pct) .option('--order_type ', 'order type to use (maker/taker)', /^(maker|taker)$/i, conf.order_type) .option('--size ', 'sell specific size of currency') .option('--markup_sell_pct ', '% to mark up sell price', Number, conf.markup_sell_pct) .option('--order_adjust_time ', 'adjust ask on this interval to keep order competitive', Number, conf.order_adjust_time) .option('--order_poll_time ', 'poll order status on this interval', Number, conf.order_poll_time) .option('--max_slippage_pct ', 'avoid selling at a slippage pct above this float', conf.max_slippage_pct) .option('--debug', 'output detailed debug info') .action(function (selector, cmd) { var s = {options: minimist(process.argv)} var so = s.options delete so._ Object.keys(conf).forEach(function (k) { if (typeof cmd[k] !== 'undefined') { so[k] = cmd[k] } }) so.debug = cmd.debug so.sell_pct = cmd.pct so.selector = objectifySelector(selector || conf.selector) var order_types = ['maker', 'taker'] if (!order_types.includes(so.order_type)) { so.order_type = 'maker' } so.mode = 'live' so.strategy = conf.strategy so.stats = true var engine = engineFactory(s, conf) engine.executeSignal('sell', function (err, order) { if (err) { console.error(err) process.exit(1) } if (!order) { console.error('not enough asset balance to sell!') } process.exit() }, cmd.size) function checkOrder () { if (s.api_order) { s.exchange.getQuote({product_id: s.product_id}, function (err, quote) { if (err) { throw err } console.log('order status: '.grey + s.api_order.status.green + ', ask: '.grey + n(s.api_order.price).format('0.00000000').yellow + ', '.grey + n(s.api_order.price).subtract(quote.ask).format('0.00000000').red + ' above best ask, '.grey + n(s.api_order.filled_size).divide(s.api_order.size).format('0.0%').green + ' filled'.grey) }) } else { console.log('placing order...') } } setInterval(checkOrder, conf.order_poll_time) }) } ================================================ FILE: commands/sim.js ================================================ var tb = require('timebucket') , minimist = require('minimist') , n = require('numbro') , fs = require('fs') , path = require('path') , moment = require('moment') , colors = require('colors') , objectifySelector = require('../lib/objectify-selector') , engineFactory = require('../lib/engine') , collectionService = require('../lib/services/collection-service') , jsonexport = require('jsonexport') , _ = require('lodash') module.exports = function (program, conf) { program .command('sim [selector]') .allowUnknownOption() .description('run a simulation on backfilled data') .option('--conf ', 'path to optional conf overrides file') .option('--strategy ', 'strategy to use', String, conf.strategy) .option('--order_type ', 'order type to use (maker/taker)', /^(maker|taker)$/i, conf.order_type) .option('--reverse', 'use this and all your signals(buy/sell) will be switch! TAKE CARE!', Boolean, false) .option('--filename ', 'filename for the result output (ex: result.html). "none" to disable', String, conf.filename) .option('--start ', 'start ("YYYYMMDDhhmm")') .option('--end ', 'end ("YYYYMMDDhhmm")') .option('--days ', 'set duration by day count', Number, conf.days) .option('--currency_capital ', 'amount of start capital in currency', Number, conf.currency_capital) .option('--asset_capital ', 'amount of start capital in asset', Number, conf.asset_capital) .option('--avg_slippage_pct ', 'avg. amount of slippage to apply to trades', Number, conf.avg_slippage_pct) .option('--buy_pct ', 'buy with this % of currency balance', Number, conf.buy_pct) .option('--sell_pct ', 'sell with this % of asset balance', Number, conf.sell_pct) .option('--markdown_buy_pct ', '% to mark down buy price', Number, conf.markdown_buy_pct) .option('--markup_sell_pct ', '% to mark up sell price', Number, conf.markup_sell_pct) .option('--order_adjust_time ', 'adjust bid/ask on this interval to keep orders competitive', Number, conf.order_adjust_time) .option('--order_poll_time ', 'poll order status on this interval', Number, conf.order_poll_time) .option('--sell_cancel_pct ', 'cancels the sale if the price is between this percentage (for more or less)', Number, conf.sell_cancel_pct) .option('--sell_stop_pct ', 'sell if price drops below this % of bought price', Number, conf.sell_stop_pct) .option('--buy_stop_pct ', 'buy if price surges above this % of sold price', Number, conf.buy_stop_pct) .option('--profit_stop_enable_pct ', 'enable trailing sell stop when reaching this % profit', Number, conf.profit_stop_enable_pct) .option('--profit_stop_pct ', 'maintain a trailing stop this % below the high-water mark of profit', Number, conf.profit_stop_pct) .option('--max_sell_loss_pct ', 'avoid selling at a loss pct under this float', conf.max_sell_loss_pct) .option('--max_buy_loss_pct ', 'avoid buying at a loss pct over this float', conf.max_buy_loss_pct) .option('--max_slippage_pct ', 'avoid selling at a slippage pct above this float', conf.max_slippage_pct) .option('--symmetrical', 'reverse time at the end of the graph, normalizing buy/hold to 0', conf.symmetrical) .option('--rsi_periods ', 'number of periods to calculate RSI at', Number, conf.rsi_periods) .option('--exact_buy_orders', 'instead of only adjusting maker buy when the price goes up, adjust it if price has changed at all') .option('--exact_sell_orders', 'instead of only adjusting maker sell when the price goes down, adjust it if price has changed at all') .option('--disable_options', 'disable printing of options') .option('--quarentine_time ', 'For loss trade, set quarentine time for cancel buys', Number, conf.quarentine_time) .option('--enable_stats', 'enable printing order stats') .option('--backtester_generation ','creates a json file in simulations with the generation number', Number, -1) .option('--verbose', 'print status lines on every period') .option('--silent', 'only output on completion (can speed up sim)') .action(function (selector, cmd) { var s = { options: minimist(process.argv) } var so = s.options if (!so.quarentine_time) { so.quarentine_time = 0 } delete so._ if (cmd.conf) { var overrides = require(path.resolve(process.cwd(), cmd.conf)) Object.keys(overrides).forEach(function (k) { so[k] = overrides[k] }) } Object.keys(conf).forEach(function (k) { if (!_.isUndefined(cmd[k])) { so[k] = cmd[k] } }) var tradesCollection = collectionService(conf).getTrades() var simResults = collectionService(conf).getSimResults() var eventBus = conf.eventBus if (so.start) { so.start = moment(so.start, 'YYYYMMDDhhmm').valueOf() if (so.days && !so.end) { so.end = tb(so.start).resize('1d').add(so.days).toMilliseconds() } } if (so.end) { so.end = moment(so.end, 'YYYYMMDDhhmm').valueOf() if (so.days && !so.start) { so.start = tb(so.end).resize('1d').subtract(so.days).toMilliseconds() } } if (!so.start && so.days) { var d = tb('1d') so.start = d.subtract(so.days).toMilliseconds() } so.days = moment(so.end).diff(moment(so.start), 'days') so.stats = !!cmd.enable_stats so.show_options = !cmd.disable_options so.verbose = !!cmd.verbose so.selector = objectifySelector(selector || conf.selector) so.mode = 'sim' var engine = engineFactory(s, conf) if (!so.min_periods) so.min_periods = 1 var cursor, reversing, reverse_point var query_start = so.start ? tb(so.start).resize(so.period_length).subtract(so.min_periods + 2).toMilliseconds() : null function exitSim () { console.log() if (!s.period) { console.error('no trades found! try running `zenbot backfill ' + so.selector.normalized + '` first') process.exit(1) } var option_keys = Object.keys(so) var output_lines = [] option_keys.sort(function (a, b) { if (a < b) return -1 return 1 }) var options = {} option_keys.forEach(function (k) { options[k] = so[k] }) let options_output = options options_output.simresults = {} if (s.my_trades.length) { s.my_trades.push({ price: s.period.close, size: s.balance.asset, type: 'sell', time: s.period.time }) } s.balance.currency = n(s.net_currency).add(n(s.period.close).multiply(s.balance.asset)).format('0.00000000') s.balance.asset = 0 s.lookback.unshift(s.period) var profit = s.start_capital ? n(s.balance.currency).subtract(s.start_capital).divide(s.start_capital) : n(0) output_lines.push('end balance: ' + n(s.balance.currency).format('0.00000000').yellow + ' (' + profit.format('0.00%') + ')') //console.log('start_capital', s.start_capital) //console.log('start_price', n(s.start_price).format('0.00000000')) //console.log('close', n(s.period.close).format('0.00000000')) var buy_hold = s.start_price ? n(s.period.close).multiply(n(s.start_capital).divide(s.start_price)) : n(s.balance.currency) //console.log('buy hold', buy_hold.format('0.00000000')) var buy_hold_profit = s.start_capital ? n(buy_hold).subtract(s.start_capital).divide(s.start_capital) : n(0) output_lines.push('buy hold: ' + buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')') output_lines.push('vs. buy hold: ' + n(s.balance.currency).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow) output_lines.push(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)') var last_buy var losses = 0, sells = 0 s.my_trades.forEach(function (trade) { if (trade.type === 'buy') { last_buy = trade.price } else { if (last_buy && trade.price < last_buy) { losses++ } sells++ } }) if (s.my_trades.length) { output_lines.push('win/loss: ' + (sells - losses) + '/' + losses) output_lines.push('error rate: ' + (sells ? n(losses).divide(sells).format('0.00%') : '0.00%').yellow) } options_output.simresults.start_capital = s.start_capital options_output.simresults.last_buy_price = s.last_buy_price options_output.simresults.last_assest_value = s.period.close options_output.net_currency = s.net_currency options_output.simresults.asset_capital = s.asset_capital options_output.simresults.currency = n(s.balance.currency).value() options_output.simresults.profit = profit.value() options_output.simresults.buy_hold = buy_hold.value() options_output.simresults.buy_hold_profit = buy_hold_profit.value() options_output.simresults.total_trades = s.my_trades.length options_output.simresults.length_days = s.day_count options_output.simresults.total_sells = sells options_output.simresults.total_losses = losses options_output.simresults.vs_buy_hold = n(s.balance.currency).subtract(buy_hold).divide(buy_hold).value() * 100.00 let options_json = JSON.stringify(options_output, null, 2) if (so.show_options) { output_lines.push(options_json) } output_lines.forEach(function (line) { console.log(line) }) if (so.backtester_generation >= 0) { var file_name = so.strategy.replace('_','')+'_'+ so.selector.normalized.replace('_','').toLowerCase()+'_'+so.backtester_generation fs.writeFileSync(path.resolve(__dirname, '..', 'simulations','sim_'+file_name+'.json'),options_json, {encoding: 'utf8'}) var trades_json = JSON.stringify(s.my_trades, null, 2) fs.writeFileSync(path.resolve(__dirname, '..', 'simulations','sim_trades_'+file_name+'.json'),trades_json, {encoding: 'utf8'}) jsonexport(s.my_trades,function(err, csv){ if(err) return console.log(err) fs.writeFileSync(path.resolve(__dirname, '..', 'simulations','sim_trades_'+file_name+'.csv'),csv, {encoding: 'utf8'}) }) } if (so.filename !== 'none') { var html_output = output_lines.map(function (line) { return colors.stripColors(line) }).join('\n') var data = s.lookback.slice(0, s.lookback.length - so.min_periods).map(function (period) { var data = {} var keys = Object.keys(period) for(var i = 0;i < keys.length;i++){ data[keys[i]] = period[keys[i]] } return data }) var code = 'var data = ' + JSON.stringify(data) + ';\n' code += 'var trades = ' + JSON.stringify(s.my_trades) + ';\n' var tpl = fs.readFileSync(path.resolve(__dirname, '..', 'templates', 'sim_result.html.tpl'), {encoding: 'utf8'}) var out = tpl .replace('{{code}}', code) .replace('{{trend_ema_period}}', so.trend_ema || 36) .replace('{{output}}', html_output) .replace(/\{\{symbol\}\}/g, so.selector.normalized + ' - zenbot ' + require('../package.json').version) var out_target = so.filename || 'simulations/sim_result_' + so.selector.normalized +'_' + new Date().toISOString().replace(/T/, '_').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').replace(/20/, '') + '_UTC.html' fs.writeFileSync(out_target, out) console.log('wrote', out_target) } simResults.insertOne(options_output) .then(() => { process.exit(0) }) .catch((err) => { console.error(err) process.exit(0) }) } var getNext = async () => { var opts = { query: { selector: so.selector.normalized }, sort: { time: 1 }, limit: 100, timeout: false } if (so.end) { opts.query.time = { $lte: so.end } } if (cursor) { if (reversing) { opts.query.time = {} opts.query.time['$lt'] = cursor if (query_start) { opts.query.time['$gte'] = query_start } opts.sort = { time: -1 } } else { if (!opts.query.time) opts.query.time = {} opts.query.time['$gt'] = cursor } } else if (query_start) { if (!opts.query.time) opts.query.time = {} opts.query.time['$gte'] = query_start } var collectionCursor = tradesCollection .find(opts.query) .sort(opts.sort) .limit(opts.limit) var totalTrades = await collectionCursor.count(true) const collectionCursorStream = collectionCursor.stream() var numTrades = 0 var lastTrade var onCollectionCursorEnd = () => { if (numTrades === 0) { if (so.symmetrical && !reversing) { reversing = true reverse_point = cursor return getNext() } engine.exit(exitSim) return } else { if (reversing) { cursor = lastTrade.orig_time } else { cursor = lastTrade.time } } collectionCursorStream.close() return getNext() } if(totalTrades === 0) { onCollectionCursorEnd() } collectionCursorStream.on('data', function(trade) { lastTrade = trade numTrades++ if (so.symmetrical && reversing) { trade.orig_time = trade.time trade.time = reverse_point + (reverse_point - trade.time) } eventBus.emit('trade', trade) if (numTrades && totalTrades && totalTrades == numTrades) { onCollectionCursorEnd() } }) } return getNext() }) } ================================================ FILE: commands/trade.js ================================================ var tb = require('timebucket') , minimist = require('minimist') , n = require('numbro') , fs = require('fs') , path = require('path') , spawn = require('child_process').spawn , moment = require('moment') , crypto = require('crypto') , readline = require('readline') , colors = require('colors') , z = require('zero-fill') , cliff = require('cliff') , output = require('../lib/output') , objectifySelector = require('../lib/objectify-selector') , engineFactory = require('../lib/engine') , collectionService = require('../lib/services/collection-service') , debug = require('../lib/debug') module.exports = function (program, conf) { program .command('trade [selector]') .allowUnknownOption() .description('run trading bot against live market data') .option('--conf ', 'path to optional conf overrides file') .option('--strategy ', 'strategy to use', String, conf.strategy) .option('--order_type ', 'order type to use (maker/taker)', /^(maker|taker)$/i, conf.order_type) .option('--paper', 'use paper trading mode (no real trades will take place)', Boolean, false) .option('--manual', 'watch price and account balance, but do not perform trades automatically', Boolean, false) .option('--reverse', 'use this and all your signals(buy/sell) will be switch! TAKE CARE!', Boolean, false) .option('--non_interactive', 'disable keyboard inputs to the bot', Boolean, false) .option('--filename ', 'filename for the result output (ex: result.html). "none" to disable', String, conf.filename) .option('--currency_capital ', 'for paper trading, amount of start capital in currency', Number, conf.currency_capital) .option('--asset_capital ', 'for paper trading, amount of start capital in asset', Number, conf.asset_capital) .option('--avg_slippage_pct ', 'avg. amount of slippage to apply to paper trades', Number, conf.avg_slippage_pct) .option('--buy_pct ', 'buy with this % of currency balance', Number, conf.buy_pct) .option('--deposit ', 'absolute initial capital (in currency) at the bots disposal (previously --buy_max_amt)', Number, conf.deposit) .option('--sell_pct ', 'sell with this % of asset balance', Number, conf.sell_pct) .option('--markdown_buy_pct ', '% to mark down buy price', Number, conf.markdown_buy_pct) .option('--markup_sell_pct ', '% to mark up sell price', Number, conf.markup_sell_pct) .option('--order_adjust_time ', 'adjust bid/ask on this interval to keep orders competitive', Number, conf.order_adjust_time) .option('--order_poll_time ', 'poll order status on this interval', Number, conf.order_poll_time) .option('--sell_stop_pct ', 'sell if price drops below this % of bought price', Number, conf.sell_stop_pct) .option('--buy_stop_pct ', 'buy if price surges above this % of sold price', Number, conf.buy_stop_pct) .option('--profit_stop_enable_pct ', 'enable trailing sell stop when reaching this % profit', Number, conf.profit_stop_enable_pct) .option('--profit_stop_pct ', 'maintain a trailing stop this % below the high-water mark of profit', Number, conf.profit_stop_pct) .option('--sell_cancel_pct ', 'cancels the sale if the price is between this percentage (for more or less)', Number, conf.sell_cancel_pct) .option('--max_sell_loss_pct ', 'avoid selling at a loss pct under this float', conf.max_sell_loss_pct) .option('--max_buy_loss_pct ', 'avoid buying at a loss pct over this float', conf.max_buy_loss_pct) .option('--max_slippage_pct ', 'avoid selling at a slippage pct above this float', conf.max_slippage_pct) .option('--rsi_periods ', 'number of periods to calculate RSI at', Number, conf.rsi_periods) .option('--poll_trades ', 'poll new trades at this interval in ms', Number, conf.poll_trades) .option('--currency_increment ', 'Currency increment, if different than the asset increment', String, null) .option('--keep_lookback_periods ', 'Keep this many lookback periods max. ', Number, conf.keep_lookback_periods) .option('--exact_buy_orders', 'instead of only adjusting maker buy when the price goes up, adjust it if price has changed at all') .option('--exact_sell_orders', 'instead of only adjusting maker sell when the price goes down, adjust it if price has changed at all') .option('--use_prev_trades', 'load and use previous trades for stop-order triggers and loss protection') .option('--min_prev_trades ', 'minimum number of previous trades to load if use_prev_trades is enabled, set to 0 to disable and use trade time instead', Number, conf.min_prev_trades) .option('--disable_stats', 'disable printing order stats') .option('--reset_profit', 'start new profit calculation from 0') .option('--use_fee_asset', 'Using separated asset to pay for fees. Such as binance\'s BNB or Huobi\'s HT', Boolean, false) .option('--run_for ', 'Execute for a period of minutes then exit with status 0', String, null) .option('--interval_trade ', 'The interval trade time', Number, conf.interval_trade) .option('--quarentine_time ', 'For loss trade, set quarentine time for cancel buys', Number, conf.quarentine_time) .option('--debug', 'output detailed debug info') .action(function (selector, cmd) { var raw_opts = minimist(process.argv) var s = {options: JSON.parse(JSON.stringify(raw_opts))} var so = s.options if (so.run_for) { var botStartTime = moment().add(so.run_for, 'm') } if (!so.interval_trade) { so.interval_trade = 10 } if (!so.quarentine_time) { so.quarentine_time = 0 } delete so._ if (cmd.conf) { var overrides = require(path.resolve(process.cwd(), cmd.conf)) Object.keys(overrides).forEach(function (k) { so[k] = overrides[k] }) } Object.keys(conf).forEach(function (k) { if (typeof cmd[k] !== 'undefined') { so[k] = cmd[k] } }) so.currency_increment = cmd.currency_increment so.keep_lookback_periods = cmd.keep_lookback_periods so.use_prev_trades = (cmd.use_prev_trades||conf.use_prev_trades) so.min_prev_trades = cmd.min_prev_trades so.debug = cmd.debug so.stats = !cmd.disable_stats so.mode = so.paper ? 'paper' : 'live' if (so.buy_max_amt) { console.log(('--buy_max_amt is deprecated, use --deposit instead!\n').red) so.deposit = so.buy_max_amt } so.selector = objectifySelector(selector || conf.selector) var engine = engineFactory(s, conf) var collectionServiceInstance = collectionService(conf) if (!so.min_periods) so.min_periods = 1 const keyMap = new Map() keyMap.set('b', 'limit'.grey + ' BUY'.green) keyMap.set('B', 'market'.grey + ' BUY'.green) keyMap.set('s', 'limit'.grey + ' SELL'.red) keyMap.set('S', 'market'.grey + ' SELL'.red) keyMap.set('c', 'cancel order'.grey) keyMap.set('m', 'toggle MANUAL trade in LIVE mode ON / OFF'.grey) keyMap.set('T', 'switch to \'Taker\' order type'.grey) keyMap.set('M', 'switch to \'Maker\' order type'.grey) keyMap.set('o', 'show current trade options'.grey) keyMap.set('O', 'show current trade options in a dirty view (full list)'.grey) keyMap.set('L', 'toggle DEBUG'.grey) keyMap.set('P', 'print statistical output'.grey) keyMap.set('X', 'exit program with statistical output'.grey) keyMap.set('d', 'dump statistical output to HTML file'.grey) keyMap.set('D', 'toggle automatic HTML dump to file'.grey) var pushStr = '' function listKeys() { printLog('Available command keys:', true) keyMap.forEach((value, key) => { printLog(' ' + key + ' - ' + value) }) } function listOptions () { printLog(s.exchange.name.toUpperCase() + ' exchange active trading options:'.grey, true) printLog(z(22, 'STRATEGY'.grey, ' ') + '\t' + so.strategy + '\t' + (require(`../extensions/strategies/${so.strategy}/strategy`).description).grey, true) printLog([ z(24, (so.mode === 'paper' ? so.mode.toUpperCase() : so.mode.toUpperCase()) + ' MODE'.grey, ' '), z(26, 'PERIOD'.grey, ' '), z(30, 'ORDER TYPE'.grey, ' '), z(28, 'SLIPPAGE'.grey, ' '), z(33, 'EXCHANGE FEES'.grey, ' ') ].join(''), true) printLog([ z(15, (so.mode === 'paper' ? ' ' : (so.mode === 'live' && (so.manual === false || typeof so.manual === 'undefined')) ? ' ' + 'AUTO'.black.bgRed + ' ' : ' ' + 'MANUAL'.black.bgGreen + ' '), ' '), z(13, so.period_length, ' '), z(29, (so.order_type === 'maker' ? so.order_type.toUpperCase().green : so.order_type.toUpperCase().red), ' '), z(31, (so.mode === 'paper' ? 'avg. '.grey + so.avg_slippage_pct + '%' : 'max '.grey + so.max_slippage_pct + '%'), ' '), z(20, (so.order_type === 'maker' ? so.order_type + ' ' + s.exchange.makerFee : so.order_type + ' ' + s.exchange.takerFee), ' ') ].join('')) printLog([ z(19, 'BUY %'.grey, ' '), z(20, 'SELL %'.grey, ' '), z(35, 'TRAILING STOP %'.grey, ' '), z(33, 'TRAILING DISTANCE %'.grey, ' ') ].join('')) printLog([ z(9, so.buy_pct + '%', ' '), z(9, so.sell_pct + '%', ' '), z(20, so.profit_stop_enable_pct + '%', ' '), z(20, so.profit_stop_pct + '%', ' ') ].join('')) } /* Implementing statistical Exit */ function printTrade (quit, dump, statsonly = false) { var tmp_balance = n(s.balance.currency).add(n(s.period.close).multiply(s.balance.asset)).format('0.00000000') if (quit) { if (s.my_trades.length) { s.my_trades.push({ price: s.period.close, size: s.balance.asset, type: 'sell', time: s.period.time }) } s.balance.currency = tmp_balance s.balance.asset = 0 s.lookback.unshift(s.period) } var profit = s.start_capital ? n(tmp_balance).subtract(s.start_capital).divide(s.start_capital) : n(0) var buy_hold = s.start_price ? n(s.period.close).multiply(n(s.start_capital).divide(s.start_price)) : n(tmp_balance) var buy_hold_profit = s.start_capital ? n(buy_hold).subtract(s.start_capital).divide(s.start_capital) : n(0) if (!statsonly) { console.log() var output_lines = [] output_lines.push('Strategy: ' + so.strategy) output_lines.push('Last balance: ' + n(tmp_balance).format('0.00000000').yellow + ' (' + profit.format('0.00%') + ')') output_lines.push('Buy hold: ' + buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')') output_lines.push('vs. Buy hold: ' + n(tmp_balance).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow) output_lines.push(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)') } // Build stats for UI s.stats = { profit: profit.format('0.00%'), tmp_balance: n(tmp_balance).format('0.00000000'), buy_hold: buy_hold.format('0.00000000'), buy_hold_profit: n(buy_hold_profit).format('0.00%'), day_count: s.day_count, trade_per_day: n(s.my_trades.length / s.day_count).format('0.00') } var last_buy var losses = 0, sells = 0 s.my_trades.forEach(function (trade) { if (trade.type === 'buy') { last_buy = trade.price } else { if (last_buy && trade.price < last_buy) { losses++ } sells++ } }) if (s.my_trades.length && sells > 0) { if (!statsonly) { output_lines.push('Win/Loss: ' + (sells - losses) + '/' + losses) output_lines.push('Error rate: ' + (sells ? n(losses).divide(sells).format('0.00%') : '0.00%').yellow) } //for API s.stats.win = (sells - losses) s.stats.losses = losses s.stats.error_rate = (sells ? n(losses).divide(sells).format('0.00%') : '0.00%') } if (!statsonly) { output_lines.forEach(function (line) { printLog(line) }) } if (quit || dump) { var html_output = output_lines.map(function (line) { return colors.stripColors(line) }).join('\n') var data = s.lookback.slice(0, s.lookback.length - so.min_periods).map(function (period) { var data = {} var keys = Object.keys(period) for(var i = 0; i < keys.length; i++){ data[keys[i]] = period[keys[i]] } return data }) var code = 'var data = ' + JSON.stringify(data) + ';\n' code += 'var trades = ' + JSON.stringify(s.my_trades) + ';\n' var tpl = fs.readFileSync(path.resolve(__dirname, '..', 'templates', 'sim_result.html.tpl'), {encoding: 'utf8'}) var out = tpl .replace('{{code}}', code) .replace('{{trend_ema_period}}', so.trend_ema || 36) .replace('{{output}}', html_output) .replace(/\{\{symbol\}\}/g, so.selector.normalized + ' - zenbot ' + require('../package.json').version) if (so.filename !== 'none') { var out_target var out_target_prefix = so.paper ? 'simulations/paper_result_' : 'stats/trade_result_' if(dump){ var dt = new Date().toISOString() //ymd var today = dt.slice(2, 4) + dt.slice(5, 7) + dt.slice(8, 10) out_target = so.filename || out_target_prefix + so.selector.normalized +'_' + today + '_UTC.html' fs.writeFileSync(out_target, out) }else out_target = so.filename || out_target_prefix + so.selector.normalized +'_' + new Date().toISOString().replace(/T/, '_').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').replace(/20/, '') + '_UTC.html' fs.writeFileSync(out_target, out) console.log('\nwrote'.grey, out_target) } if(quit) process.exit(0) } } /* The end of printTrade */ /* Implementing statistical status dump every 10 secs */ var shouldSaveStats = false function toggleStats(){ shouldSaveStats = !shouldSaveStats if(shouldSaveStats) printLog('Auto stats dump enabled') else printLog('Auto stats dump disabled') } function saveStatsLoop(){ saveStats() setTimeout(function () { saveStatsLoop() }, 10000) } saveStatsLoop() function saveStats () { if(!shouldSaveStats) return var output_lines = [] var tmp_balance = n(s.balance.currency).add(n(s.period.close).multiply(s.balance.asset)).format('0.00000000') var profit = s.start_capital ? n(tmp_balance).subtract(s.start_capital).divide(s.start_capital) : n(0) output_lines.push('Strategy: ' + so.strategy) output_lines.push('Last balance: ' + n(tmp_balance).format('0.00000000').yellow + ' (' + profit.format('0.00%') + ')') var buy_hold = s.start_price ? n(s.period.close).multiply(n(s.start_capital).divide(s.start_price)) : n(tmp_balance) var buy_hold_profit = s.start_capital ? n(buy_hold).subtract(s.start_capital).divide(s.start_capital) : n(0) output_lines.push('Buy hold: ' + buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')') output_lines.push('vs. Buy hold: ' + n(tmp_balance).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow) output_lines.push(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)') // Build stats for UI s.stats = { profit: profit.format('0.00%'), tmp_balance: n(tmp_balance).format('0.00000000'), buy_hold: buy_hold.format('0.00000000'), buy_hold_profit: n(buy_hold_profit).format('0.00%'), day_count: s.day_count, trade_per_day: n(s.my_trades.length / s.day_count).format('0.00') } var last_buy var losses = 0, sells = 0 s.my_trades.forEach(function (trade) { if (trade.type === 'buy') { last_buy = trade.price } else { if (last_buy && trade.price < last_buy) { losses++ } sells++ } }) if (s.my_trades.length && sells > 0) { output_lines.push('Win/Loss: ' + (sells - losses) + '/' + losses) output_lines.push('Error rate: ' + (sells ? n(losses).divide(sells).format('0.00%') : '0.00%').yellow) //for API s.stats.win = (sells - losses) s.stats.losses = losses s.stats.error_rate = (sells ? n(losses).divide(sells).format('0.00%') : '0.00%') } var html_output = output_lines.map(function (line) { return colors.stripColors(line) }).join('\n') var data = s.lookback.slice(0, s.lookback.length - so.min_periods).map(function (period) { var data = {} var keys = Object.keys(period) for(var i = 0; i < keys.length; i++){ data[keys[i]] = period[keys[i]] } return data }) var code = 'var data = ' + JSON.stringify(data) + ';\n' code += 'var trades = ' + JSON.stringify(s.my_trades) + ';\n' var tpl = fs.readFileSync(path.resolve(__dirname, '..', 'templates', 'sim_result.html.tpl'), {encoding: 'utf8'}) var out = tpl .replace('{{code}}', code) .replace('{{trend_ema_period}}', so.trend_ema || 36) .replace('{{output}}', html_output) .replace(/\{\{symbol\}\}/g, so.selector.normalized + ' - zenbot ' + require('../package.json').version) if (so.filename !== 'none') { var out_target var dt = new Date().toISOString() //ymd var today = dt.slice(2, 4) + dt.slice(5, 7) + dt.slice(8, 10) let out_target_prefix = so.paper ? 'simulations/paper_result_' : 'stats/trade_result_' out_target = so.filename || out_target_prefix + so.selector.normalized +'_' + today + '_UTC.html' fs.writeFileSync(out_target, out) //console.log('\nwrote'.grey, out_target) } } function printLog(str, cr = false) { if (str) { console.log((cr?'\n':'') + str) pushStr += str + '\n' } } function executeCommand(command) { var info = { ctrl: false } if (conf.debug) { console.log('\nCommand received: ' + command) } executeKey(command, info) } function executeKey(key, info) { if (key === 'l') { listKeys() } else if (key === 'b' && !info.ctrl ) { engine.executeSignal('buy') printLog('manual'.grey + ' limit ' + 'BUY'.green + ' command executed'.grey, true) } else if (key === 'B' && !info.ctrl) { engine.executeSignal('buy', null, null, false, true) printLog('manual'.grey + ' market ' + 'BUY'.green + ' command executed'.grey, true) } else if (key === 's' && !info.ctrl) { engine.executeSignal('sell') printLog('manual'.grey + ' limit ' + 'SELL'.red + ' command executed'.grey, true) } else if (key === 'S' && !info.ctrl) { engine.executeSignal('sell', null, null, false, true) printLog('manual'.grey + ' market ' + 'SELL'.red + ' command executed'.grey, true) } else if ((key === 'c' || key === 'C') && !info.ctrl) { delete s.buy_order delete s.sell_order printLog('manual'.grey + ' order cancel' + ' command executed'.grey, true) } else if (key === 'm' && !info.ctrl && so.mode === 'live') { so.manual = !so.manual printLog('MANUAL trade in LIVE mode: ' + (so.manual ? 'ON'.green.inverse : 'OFF'.red.inverse), true) } else if (key === 'T' && !info.ctrl) { so.order_type = 'taker' printLog('Taker fees activated'.bgRed, true) } else if (key === 'M' && !info.ctrl) { so.order_type = 'maker' printLog('Maker fees activated'.black.bgGreen, true) } else if (key === 'o' && !info.ctrl) { listOptions() } else if (key === 'O' && !info.ctrl) { printLog(cliff.inspect(so), true) } else if (key === 'P' && !info.ctrl) { printLog('Writing statistics...'.grey, true) printTrade(false) } else if (key === 'X' && !info.ctrl) { printLog('Exiting... ' + '\nWriting statistics...'.grey, true) printTrade(true) } else if (key === 'd' && !info.ctrl) { printLog('Dumping statistics...'.grey, true) printTrade(false, true) } else if (key === 'D' && !info.ctrl) { printLog('Dumping statistics...'.grey, true) toggleStats() } else if (key === 'L' && !info.ctrl) { debug.flip() printLog('DEBUG mode: ' + (debug.on ? 'ON'.green.inverse : 'OFF'.red.inverse), true) } else if (info.name === 'c' && info.ctrl) { // @todo: cancel open orders before exit process.exit() } if (pushStr) { engine.pushMessage('Reply', colors.stripColors(pushStr)) pushStr = '' } } var order_types = ['maker', 'taker'] if (!order_types.includes(so.order_type)) { so.order_type = 'maker' } var db_cursor, trade_cursor var query_start = tb().resize(so.period_length).subtract(so.min_periods * 2).toMilliseconds() var days = Math.ceil((new Date().getTime() - query_start) / 86400000) var session = null var sessions = collectionServiceInstance.getSessions() var balances = collectionServiceInstance.getBalances() var trades = collectionServiceInstance.getTrades() var resume_markers = collectionServiceInstance.getResumeMarkers() var marker = { id: crypto.randomBytes(4).toString('hex'), selector: so.selector.normalized, from: null, to: null, oldest_time: null } marker._id = marker.id var lookback_size = 0 var my_trades_size = 0 var my_trades = collectionServiceInstance.getMyTrades() var periods = collectionServiceInstance.getPeriods() console.log('fetching pre-roll data:') var zenbot_cmd = process.platform === 'win32' ? 'zenbot.bat' : 'zenbot.sh' // Use 'win32' for 64 bit windows too var command_args = ['backfill', so.selector.normalized, '--days', days || 1] if (cmd.conf) { command_args.push('--conf', cmd.conf) } var backfiller = spawn(path.resolve(__dirname, '..', zenbot_cmd), command_args) backfiller.stdout.pipe(process.stdout) backfiller.stderr.pipe(process.stderr) backfiller.on('exit', function (code) { if (code) { process.exit(code) } function getNext () { var opts = { query: { selector: so.selector.normalized }, sort: {time: 1}, limit: 1000 } if (db_cursor) { opts.query.time = {$gt: db_cursor} } else { trade_cursor = s.exchange.getCursor(query_start) opts.query.time = {$gte: query_start} } trades.find(opts.query).limit(opts.limit).sort(opts.sort).toArray(function (err, trades) { if (err) throw err if (trades.length && so.use_prev_trades) { let prevOpts = { query: { selector: so.selector.normalized }, limit: so.min_prev_trades } if (!so.min_prev_trades) { prevOpts.query.time = {$gte : trades[0].time} } my_trades.find(prevOpts.query).sort({$natural:-1}).limit(prevOpts.limit).toArray(function (err, my_prev_trades) { if (err) throw err if (my_prev_trades.length) { s.my_prev_trades = my_prev_trades.reverse().slice(0) // simple copy, less recent executed first } }) } if (!trades.length) { var head = '------------------------------------------ INITIALIZE OUTPUT ------------------------------------------' console.log(head) output(conf).initializeOutput(s) var minuses = Math.floor((head.length - so.mode.length - 19) / 2) console.log('-'.repeat(minuses) + ' STARTING ' + so.mode.toUpperCase() + ' TRADING ' + '-'.repeat(minuses + (minuses % 2 == 0 ? 0 : 1))) if (so.mode === 'paper') { console.log('!!! Paper mode enabled. No real trades are performed until you remove --paper from the startup command.') } console.log('Press ' + ' l '.inverse + ' to list available commands.') engine.syncBalance(function (err) { if (err) { if (err.desc) console.error(err.desc) if (err.body) console.error(err.body) throw err } session = { id: crypto.randomBytes(4).toString('hex'), selector: so.selector.normalized, started: new Date().getTime(), mode: so.mode, options: so } session._id = session.id sessions.find({selector: so.selector.normalized}).limit(1).sort({started: -1}).toArray(function (err, prev_sessions) { if (err) throw err var prev_session = prev_sessions[0] if (prev_session && !cmd.reset_profit) { if (prev_session.orig_capital && prev_session.orig_price && prev_session.deposit === so.deposit && ((so.mode === 'paper' && !raw_opts.currency_capital && !raw_opts.asset_capital) || (so.mode === 'live' && prev_session.balance.asset == s.balance.asset && prev_session.balance.currency == s.balance.currency))) { s.orig_capital = session.orig_capital = prev_session.orig_capital s.orig_price = session.orig_price = prev_session.orig_price if (so.mode === 'paper') { s.balance = prev_session.balance } } } if(s.lookback.length > so.keep_lookback_periods){ s.lookback.splice(-1,1) } forwardScan() setInterval(forwardScan, so.poll_trades) if (!so.non_interactive) { engine.onMessage(executeCommand) } readline.emitKeypressEvents(process.stdin) if (!so.non_interactive && process.stdin.setRawMode) { process.stdin.setRawMode(true) process.stdin.on('keypress', executeKey) } }) }) return } db_cursor = trades[trades.length - 1].time trade_cursor = s.exchange.getCursor(trades[trades.length - 1]) engine.update(trades, true, function (err) { if (err) throw err setImmediate(getNext) }) }) } engine.writeHeader() getNext() }) var prev_timeout = null function forwardScan () { function saveSession () { engine.syncBalance(function (err) { if (!err && s.balance.asset === undefined) { // TODO not the nicest place to verify the state, but did not found a better one throw new Error('Error during syncing balance. Please check your API-Key') } if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error syncing balance') if (err.desc) console.error(err.desc) if (err.body) console.error(err.body) console.error(err) } if (botStartTime && botStartTime - moment() < 0 ) { // Not sure if I should just handle exit code directly or thru printTrade. Decided on printTrade being if code is added there for clean exits this can just take advantage of it. engine.exit(() => { printTrade(true) }) } session.updated = new Date().getTime() session.balance = s.balance session.start_capital = s.start_capital session.start_price = s.start_price session.num_trades = s.my_trades.length if (so.deposit) session.deposit = so.deposit if (!session.orig_capital) session.orig_capital = s.start_capital if (!session.orig_price) session.orig_price = s.start_price if (s.period) { session.price = s.period.close var d = tb().resize(conf.balance_snapshot_period) var b = { id: so.selector.normalized + '-' + d.toString(), selector: so.selector.normalized, time: d.toMilliseconds(), currency: s.balance.currency, asset: s.balance.asset, price: s.period.close, start_capital: session.orig_capital, start_price: session.orig_price, } b._id = b.id b.consolidated = n(s.balance.asset).multiply(s.period.close).add(s.balance.currency).value() b.profit = (b.consolidated - session.orig_capital) / session.orig_capital b.buy_hold = s.period.close * (session.orig_capital / session.orig_price) b.buy_hold_profit = (b.buy_hold - session.orig_capital) / session.orig_capital b.vs_buy_hold = (b.consolidated - b.buy_hold) / b.buy_hold conf.output.api.on && printTrade(false, false, true) if (so.mode === 'live') { balances.replaceOne({_id: b.id}, b, {upsert: true}, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving balance') console.error(err) } }) } session.balance = b } else { session.balance = { currency: s.balance.currency, asset: s.balance.asset } } sessions.replaceOne({_id: session.id}, session, {upsert: true}, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving session') console.error(err) } if (s.period) { engine.writeReport(true) } else { readline.clearLine(process.stdout) readline.cursorTo(process.stdout, 0) process.stdout.write('Waiting on first live trade to display reports, could be a few minutes ...') } }) }) } var opts = { product_id: so.selector.product_id, from: trade_cursor + 1 } s.exchange.getTrades(opts, function (err, trades) { if (err) { if (err.code === 'ETIMEDOUT' || err.code === 'ENOTFOUND' || err.code === 'ECONNRESET') { if (prev_timeout) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - getTrades request timed out. retrying...') } prev_timeout = true } else if (err.code === 'HTTP_STATUS') { if (prev_timeout) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - getTrades request failed: ' + err.message + '. retrying...') } prev_timeout = true } else { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - getTrades request failed. retrying...') console.error(err) } return } prev_timeout = null if (trades.length) { trades.sort(function (a, b) { if (a.time > b.time) return -1 if (a.time < b.time) return 1 return 0 }) trades.forEach(function (trade) { var this_cursor = s.exchange.getCursor(trade) trade_cursor = Math.max(this_cursor, trade_cursor) saveTrade(trade) }) engine.update(trades, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving session') console.error(err) } resume_markers.replaceOne({_id: marker.id}, marker, {upsert: true}, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving marker') console.error(err) } }) if (s.my_trades.length > my_trades_size) { s.my_trades.slice(my_trades_size).forEach(function (my_trade) { my_trade.id = crypto.randomBytes(4).toString('hex') my_trade._id = my_trade.id my_trade.selector = so.selector.normalized my_trade.session_id = session.id my_trade.mode = so.mode my_trades.insertOne(my_trade, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving my_trade') console.error(err) } }) }) my_trades_size = s.my_trades.length } function savePeriod (period) { if (!period.id) { period.id = crypto.randomBytes(4).toString('hex') period.selector = so.selector.normalized period.session_id = session.id } period._id = period.id periods.replaceOne({_id: period.id}, period, {upsert: true}, function (err) { if (err) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving my_trade') console.error(err) } }) } if (s.lookback.length > lookback_size) { savePeriod(s.lookback[0]) lookback_size = s.lookback.length } if (s.period) { savePeriod(s.period) } saveSession() }) } else { trade_cursor += parseInt(so.poll_trades) saveSession() } }) function saveTrade (trade) { trade.id = so.selector.normalized + '-' + String(trade.trade_id) trade._id = trade.id trade.selector = so.selector.normalized if (!marker.from) { marker.from = trade_cursor marker.oldest_time = trade.time marker.newest_time = trade.time } marker.to = marker.to ? Math.max(marker.to, trade_cursor) : trade_cursor marker.newest_time = Math.max(marker.newest_time, trade.time) trades.insertOne(trade, function (err) { // ignore duplicate key errors if (err && err.code !== 11000) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - error saving trade') console.error(err) } }) } } }) } ================================================ FILE: conf-sample.js ================================================ var c = module.exports = {} // mongo configuration c.mongo = {} c.mongo.db = process.env.ZENBOT_MONGODB_DATABASE || 'zenbot4' // Must provide EITHER c.mongo.connectionString OR c.mongo.host,port,username,password c.mongo.connectionString = process.env.ZENBOT_MONGODB_CONNECTION_STRING || null // The following is not needed when c.mongo.connectionString is provided: c.mongo.host = process.env.ZENBOT_MONGODB_HOST || 'localhost' c.mongo.port = process.env.ZENBOT_MONGODB_PORT || 27017 c.mongo.username = process.env.ZENBOT_MONGO_USERNAME || null c.mongo.password = process.env.ZENBOT_MONGO_PASSWORD || null // when using mongodb replication, i.e. when running a mongodb cluster, you can define your replication set here; when you are not using replication (most of the users), just set it to `null` (default). c.mongo.replicaSet = process.env.ZENBOT_MONGO_REPLICASET || null c.mongo.authMechanism = process.env.ZENBOT_MONGO_AUTH_MECHANISM || null // default selector. only used if omitting [selector] argument from a command. c.selector = process.env.ZENBOT_DEFAULT_SELECTOR || 'gdax.BTC-USD' // name of default trade strategy c.strategy = process.env.ZENBOT_DEFAULT_STRATEGY || 'trend_ema' // Exchange API keys: // to enable GDAX trading, enter your API credentials: c.gdax = {} c.gdax.key = process.env.ZENBOT_GDAX_API_KEY || 'YOUR-API-KEY' c.gdax.b64secret = process.env.ZENBOT_GDAX_B64_SECRET || 'YOUR-API-SECRET' c.gdax.passphrase = process.env.ZENBOT_GDAX_PASSPHRASE || 'YOUR-API-PASSPHRASE' // set to true to trade on the sandbox platform API c.gdax.sandbox = process.env.ZENBOT_GDAX_SANDBOX || false // to enable Poloniex trading, enter your API credentials: c.poloniex = {} c.poloniex.key = process.env.ZENBOT_POLONIEX_API_KEY || 'YOUR-API-KEY' c.poloniex.secret = process.env.ZENBOT_POLONIEX_SECRET || 'YOUR-API-SECRET' // please note: poloniex does not support market orders via the API // to enable Kraken trading, enter your API credentials: c.kraken = {} c.kraken.key = process.env.ZENBOT_KRAKEN_API_KEY || 'YOUR-API-KEY' c.kraken.secret = process.env.ZENBOT_KRAKEN_SECRET || 'YOUR-API-SECRET' // Please read API TOS on https://www.kraken.com/u/settings/api c.kraken.tosagree = process.env.ZENBOT_KRAKEN_TOS_AGREE || 'disagree' // to enable Binance trading, enter your API credentials: c.binance = {} c.binance.key = process.env.ZENBOT_BINANCE_API_KEY || 'YOUR-API-KEY' c.binance.secret = process.env.ZENBOT_BINANCE_SECRET || 'YOUR-API-SECRET' // to enable Binance US trading, enter your API credentials: c.binanceus = {} c.binanceus.key = 'YOUR-API-KEY' c.binanceus.secret = 'YOUR-SECRET' // to enable Bittrex trading, enter your API credentials: c.bittrex = {} c.bittrex.key = process.env.ZENBOT_BITTREX_API_KEY || 'YOUR-API-KEY' c.bittrex.secret = process.env.ZENBOT_BITTREX_SECRET || 'YOUR-API-SECRET' // make sure to give your API key access to only: "Trade Limit" and "Read Info", // please note that this might change in the future. // please note that bittrex API is limited, you cannot use backfills or sims (paper/live trading only) // to enable Bitfinex trading, enter your API credentials: c.bitfinex = {} c.bitfinex.key = process.env.ZENBOT_BITFINEX_API_KEY || 'YOUR-API-KEY' c.bitfinex.secret = process.env.ZENBOT_BITFINEX_SECRET || 'YOUR-API-SECRET' // May use 'exchange' or 'margin' wallet balances c.bitfinex.wallet = process.env.ZENBOT_BITFINEX_WALLET || 'exchange' // to enable Bitstamp trading, enter your API credentials: c.bitstamp = {} c.bitstamp.key = process.env.ZENBOT_BITSTAMP_API_KEY || 'YOUR-API-KEY' c.bitstamp.secret = process.env.ZENBOT_BITSTAMP_SECRET || 'YOUR-API-SECRET' // A client ID is required on Bitstamp c.bitstamp.client_id = process.env.ZENBOT_BITSTAMP_CLIENT_ID || 'YOUR-CLIENT-ID' // to enable CEX.IO trading, enter your API credentials: c.cexio = {} c.cexio.username = process.env.ZENBOT_CEXIO_CLIENT_ID || 'YOUR-CLIENT-ID' c.cexio.key = process.env.ZENBOT_CEXIO_API_KEY || 'YOUR-API-KEY' c.cexio.secret = process.env.ZENBOT_CEXIO_SECRET || 'YOUR-API-SECRET' // to enable Gemini trading, enter your API credentials: c.gemini = {} c.gemini.key = process.env.ZENBOT_GEMINI_API_KEY || 'YOUR-API-KEY' c.gemini.secret = process.env.ZENBOT_GEMINI_SECRET || 'YOUR-API-SECRET' // set to false to trade on the live platform API c.gemini.sandbox = process.env.ZENBOT_GEMINI_SANDBOX || true // to enable hitBTC trading, enter your API credentials: c.hitbtc = {} c.hitbtc.key = process.env.ZENBOT_HITBTC_API_KEY || 'YOUR-API-KEY' c.hitbtc.secret = process.env.ZENBOT_HITBTC_SECRET || 'YOUR-API-SECRET' // to enable therock trading, enter your API credentials: c.therock = {} c.therock.key = process.env.ZENBOT_THEROCK_API_KEY || 'YOUR-API-KEY' c.therock.secret = process.env.ZENBOT_THEROCK_SECRET || 'YOUR-API-SECRET' // Optional stop-order triggers: // sell if price drops below this % of bought price (0 to disable) c.sell_stop_pct = process.env.ZENBOT_SELL_STOP_PCT || 0 // buy if price surges above this % of sold price (0 to disable) c.buy_stop_pct = process.env.ZENBOT_BUY_STOP_PCT || 0 // enable trailing sell stop when reaching this % profit (0 to disable) c.profit_stop_enable_pct = process.env.ZENBOT_PROFIT_STOP_ENABLE_PCT || 0 // maintain a trailing stop this % below the high-water mark of profit c.profit_stop_pct = process.env.ZENBOT_PROFIT_STOP_PCT || 1 // Order execution rules: // avoid trading at a slippage above this pct c.max_slippage_pct = process.env.ZENBOT_MAX_SLIPPAGE_PCT || 5 // buy with this % of currency balance (WARNING : sim won't work properly if you set this value to 100) c.buy_pct = process.env.ZENBOT_BUY_PCT || 99 // sell with this % of asset balance (WARNING : sim won't work properly if you set this value to 100) c.sell_pct = process.env.ZENBOT_SELL_PCT || 99 // ms to adjust non-filled order after c.order_adjust_time = process.env.ZENBOT_ORDER_ADJUST_TIME || 5000 // avoid selling at a loss below this pct set to 0 to ensure selling at a higher price... c.max_sell_loss_pct = process.env.ZENBOT_MAX_SELL_LOSS_PCT || 99 // avoid buying at a loss above this pct set to 0 to ensure buying at a lower price... c.max_buy_loss_pct = process.env.ZENBOT_MAX_BUY_LOSS_PCT || 99 // ms to poll order status c.order_poll_time = process.env.ZENBOT_ORDER_POLL_TIME || 5000 // ms to wait for settlement (after an order cancel) c.wait_for_settlement = process.env.ZENBOT_WAIT_FOR_SETTLEMENT || 5000 // % to mark down buy price for orders c.markdown_buy_pct = process.env.ZENBOT_MARKDOWN_BUY_PCT || 0 // % to mark up sell price for orders c.markup_sell_pct = process.env.ZENBOT_MARKUP_SELL_PCT || 0 // become a market taker (high fees) or a market maker (low fees) c.order_type = process.env.ZENBOT_ORDER_TYPE || 'maker' // when supported by the exchange, use post only type orders. c.post_only = process.env.ZENBOT_POST_ONLY || true // use separated fee currency such as binance's BNB. c.use_fee_asset = process.env.ZENBOT_USE_FEE_ASSET || false // Misc options: // default # days for backfill and sim commands c.days = process.env.ZENBOT_DAYS || 14 // defaults to a high number of lookback periods c.keep_lookback_periods = process.env.ZENBOT_KEEP_LOOKBACK_PERIODS || 50000 // ms to poll new trades at c.poll_trades = process.env.ZENBOT_POLL_TRADES || 30000 // amount of currency to start simulations with c.currency_capital = process.env.ZENBOT_CURRENCY_CAPITAL || 1000 // amount of asset to start simulations with c.asset_capital = process.env.ZENBOT_ASSET_CAPITAL || 0 // for sim, reverse time at the end of the graph, normalizing buy/hold to 0 c.symmetrical = process.env.ZENBOT_SYMMETRICAL || false // number of periods to calculate RSI at c.rsi_periods = process.env.ZENBOT_RSI_PERIODS || 14 // period to record balances for stats c.balance_snapshot_period = process.env.ZENBOT_BALANCE_SNAPSHOT_PERIOD || '15m' // avg. amount of slippage to apply to sim trades c.avg_slippage_pct = process.env.ZENBOT_AVG_SLIPPAGE_PCT || 0.045 // time to leave an order open, default to 1 day (this feature is not supported on all exchanges, currently: GDAX) c.cancel_after = process.env.ZENBOT_CANCEL_AFTER || 'day' // load and use previous trades for stop-order triggers and loss protection (live/paper mode only) c.use_prev_trades = process.env.ZENBOT_USE_PREV_TRADES || false // minimum number of previous trades to load if use_prev_trades is enabled, set to 0 to disable and use trade time instead c.min_prev_trades = process.env.ZENBOT_MIN_PREV_TRADES || 0 // Notifiers: c.notifiers = {} //common c.notifiers.only_completed_trades = process.env.ZENBOT_NOTIFY_ONLY_COMPLETED_TRADES || false // Filter to notifier's messages for getting Commpleted Trades info. // xmpp config c.notifiers.xmpp = {} c.notifiers.xmpp.on = process.env.ZENBOT_XMPP_ENABLE || false // false xmpp disabled; true xmpp enabled (credentials should be correct) c.notifiers.xmpp.jid = process.env.ZENBOT_XMPP_JID || 'trader@domain.com' c.notifiers.xmpp.password = process.env.ZENBOT_XMPP_PASSWORD || '' c.notifiers.xmpp.host = process.env.ZENBOT_XMPP_HOST || 'domain.com' c.notifiers.xmpp.port = process.env.ZENBOT_XMPP_PORT || 5222 c.notifiers.xmpp.to = process.env.ZENBOT_XMPP_TO || 'MeMyselfAndI@domain.com' // end xmpp configs // pushbullets configs c.notifiers.pushbullet = {} c.notifiers.pushbullet.on = process.env.ZENBOT_PUSHBULLET_ENABLE || false // false pushbullets disabled; true pushbullets enabled (key should be correct) c.notifiers.pushbullet.key = process.env.ZENBOT_PUSHBULLET_API_KEY || '' c.notifiers.pushbullet.deviceID = process.env.ZENBOT_PUSHBULLET_DEVICE_ID || '' // end pushbullets configs // ifttt configs c.notifiers.ifttt = {} c.notifiers.ifttt.on = process.env.ZENBOT_IFTTT_ENABLE || false // false ifttt disabled; true ifttt enabled (key should be correct) c.notifiers.ifttt.makerKey = process.env.ZENBOT_IFTTT_API_KEY || '' c.notifiers.ifttt.eventName = process.env.ZENBOT_IFTTT_EVENT_NAME || 'zenbot' // end ifttt configs // slack config c.notifiers.slack = {} c.notifiers.slack.on = process.env.ZENBOT_SLACK_ENABLE || false c.notifiers.slack.webhook_url = process.env.ZENBOT_SLACK_WEBHOOK_URL || '' // end slack config // ADAMANT Messenger config c.notifiers.adamant = {} c.notifiers.adamant.on = process.env.ZENBOT_ADAMANT_ENABLE || false c.notifiers.adamant.nodes = typeof process.env.ZENBOT_ADAMANT_NODES !== 'undefined' ? process.env.ZENBOT_ADAMANT_NODES.split(',') : [ 'https://endless.adamant.im', 'https://clown.adamant.im', 'https://bid.adamant.im', 'https://unusual.adamant.im', 'https://debate.adamant.im', 'http://185.231.245.26:36666', 'https://lake.adamant.im', 'http://localhost:36666' ] c.notifiers.adamant.fromPassphrase = process.env.ZENBOT_ADAMANT_FROM_PASSPHRASE || '' c.notifiers.adamant.toAddresses = typeof process.env.ZENBOT_ADAMANT_TO_ADDRESSES !== 'undefined' ? process.env.ZENBOT_ADAMANT_TO_ADDRESSES.split(',') : [''] // end ADAMANT Messenger config // discord configs c.notifiers.discord = {} c.notifiers.discord.on = process.env.ZENBOT_DISCORD_ENABLE || false // false discord disabled; true discord enabled (key should be correct) c.notifiers.discord.id = process.env.ZENBOT_DISCORD_ID || '' c.notifiers.discord.token = process.env.ZENBOT_DISCORD_TOKEN || '' c.notifiers.discord.username = process.env.ZENBOT_DISCORD_USERNAME || 'Zenbot' c.notifiers.discord.avatar_url = process.env.ZENBOT_DISCORD_AVATAR_URL || '' c.notifiers.discord.color = process.env.ZENBOT_DISCORD_COLOR || null // color as a decimal // end discord configs // prowl configs c.notifiers.prowl = {} c.notifiers.prowl.on = process.env.ZENBOT_PROWL_ENABLE || false // false prowl disabled; true prowl enabled (key should be correct) c.notifiers.prowl.key = process.env.ZENBOT_PROWL_KEY // end prowl configs // textbelt configs c.notifiers.textbelt = {} c.notifiers.textbelt.on = process.env.ZENBOT_TEXTBELT_ENABLE || false // false textbelt disabled; true textbelt enabled (key should be correct) c.notifiers.textbelt.phone = process.env.ZENBOT_TEXTBELT_PHONE c.notifiers.textbelt.key = process.env.ZENBOT_TEXTBELT_KEY // end textbelt configs // pushover configs c.notifiers.pushover = {} c.notifiers.pushover.on = process.env.ZENBOT_PUSHOVER_ENABLE || false // false pushover disabled; true pushover enabled (keys should be correct) c.notifiers.pushover.token = process.env.ZENBOT_PUSHOVER_TOKEN // create application and supply the token here c.notifiers.pushover.user = process.env.ZENBOT_PUSHOVER_USER_KEY // this is your own user's key (not application related) c.notifiers.pushover.priority = process.env.ZENBOT_PUSHOVER_PRIORITY || '0' // choose a priority to send zenbot messages with, see https://pushover.net/api#priority // end pushover configs // telegram configs c.notifiers.telegram = {} c.notifiers.telegram.on = process.env.ZENBOT_TELEGRAM_ENABLE || false // false telegram disabled; true telegram enabled (key should be correct) c.notifiers.telegram.interactive = process.env.ZENBOT_TELEGRAM_INTERACTIVE || false // true telegram is interactive c.notifiers.telegram.bot_token = process.env.ZENBOT_TELEGRAM_BOT_TOKEN c.notifiers.telegram.chat_id = process.env.ZENBOT_TELEGRAM_CHAT_ID // the id of the chat the messages should be send in // end telegram configs // output c.output = {} // REST API c.output.api = {} c.output.api.on = process.env.ZENBOT_API_ENABLE || true c.output.api.ip = process.env.ZENBOT_API_IP || '0.0.0.0' // IPv4 or IPv6 address to listen on, uses all available interfaces if omitted c.output.api.port = process.env.ZENBOT_API_PORT || 17365 ================================================ FILE: docker-compose-traefik.yml ================================================ version: '3.1' services: zenbotserver: build: context: . dockerfile: Dockerfile volumes: - ./:/app/ - /app/node_modules/ - /app/dist/ restart: always tty: true expose: - "17365" labels: - "traefik.enable=true" - "traefik.frontend.rule=Host:$(TRAEFIK_HOST_ZEN)" - "traefik.docker.network=$(TRAEFIK_NETWORK_NAME)" - "traefik.port=17365" - "traefik.frontend.auth.basic=$(BASIC_AUTH_ZEN)" networks: - internal - proxy depends_on: - mongodb environment: - MONGODB_PORT_27017_TCP_ADDR=mongodb mongodb: image: mongo:latest restart: always volumes: - ./data/db:/data/db command: mongod --smallfiles --bind_ip=0.0.0.0 --logpath=/dev/null networks: - internal expose: - 27017 # "adminMongo is a Web based user interface (GUI) to handle all your MongoDB connections/databases needs." adminmongo: image: mrvautin/adminmongo expose: - 1234 depends_on: - mongodb environment: - "CONN_NAME=zenbot_mongodb" - "DB_HOST=mongodb" - "DB_PORT=27017" - "HOST=0.0.0.0" labels: - "traefik.enable=true" - "traefik.frontend.rule=Host:$(TRAEFIK_HOST_DB)" - "traefik.docker.network=$(TRAEFIK_NETWORK_NAME)" - "traefik.port=1234" - "traefik.frontend.auth.basic=$(BASIC_AUTH_DB)" networks: - internal - proxy command: "npm start" networks: proxy: external: name: "$(TRAEFIK_NETWORK_NAME)" internal: external: false ================================================ FILE: docker-compose-windows.yml ================================================ server: image: deviavir/zenbot:unstable volumes: - ./conf.js:/app/conf.js - ./extensions:/app/extensions links: - mongodb command: [ "trade", "--paper" ] restart: always mongodb: image: mongo:latest volumes_from: - mongodb-data command: mongod --smallfiles --bind_ip=0.0.0.0 --logpath=/dev/null mongodb-data: image: mongo:latest volumes: - /data/db command: "true" ================================================ FILE: docker-compose.yml ================================================ version: "3.1" services: server: build: context: . dockerfile: Dockerfile image: deviavir/zenbot:unstable volumes: - ./simulations/:/app/simulations/ - ./conf.js:/app/conf.js:ro restart: always tty: true ports: - "17365:17365" depends_on: - mongodb environment: - ZENBOT_MONGODB_HOST=mongodb stdin_open: true mongodb: image: mongo:latest volumes: - ./database:/data/db command: mongod --bind_ip=0.0.0.0 --logpath=/dev/null # Remove below comments to use this container. "adminMongo is a Web based user interface (GUI) to handle all your MongoDB connections/databases needs." # #adminmongo: # image: mrvautin/adminmongo # links: # - mongodb # tty: true # ports: # - "127.0.0.1:1234:1234" # environment: # - CONN_NAME=zenbot_mongodb # - DB_HOST=mongodb # - DB_PORT=27017 # - HOST=0.0.0.0 # command: "npm start" ================================================ FILE: docs/FAQ.md ================================================ # Frequently Asked Questions Here are a few questions that have been asked often as well as answers from the community. If you have a question that is not answered here, feel free to ask in the [Reddit](#is-there-a-community-to-get-involved-with-zenbot) community and suggest it to be placed here. Thanks! ## Contents ### [General](#general-1) * [Is there a community to get involved with Zenbot?](#is-there-a-community-to-get-involved-with-zenbot) ### [Trading](#trading-1) * [Will I make money with Zenbot?](#will-i-make-money-with-zenbot) * [Why do simulations, paper trading, and live trading all yield different results?](#why-do-simulations-paper-trading-and-live-trading-all-yield-different-results) * [Why should I use simulations or paper trading if they do not reflect live trading?](#why-should-i-use-simulations-or-paper-trading-if-they-do-not-reflect-live-trading) * [Does Zenbot use Limit (maker) orders or Market (taker) orders?](#does-zenbot-use-limit-maker-orders-or-market-taker-orders) ### [Technical](#technical-1) * [Can I install Zenbot on Windows?](#can-i-install-zenbot-on-windows) * [Is Docker necessary when installing Zenbot?](#is-docker-necessary-when-installing-zenbot) * [How do I launch Zenbot?](#how-do-i-launch-zenbot) * [How do I update Zenbot?](#how-do-i-update-zenbot) ### [Errors](#errors-1) * [Why do I keep getting a "Nonce" error?](#why-do-i-keep-getting-a-nonce-error) * [Why do I keep getting a "JavaScript heap out of memory" error](#why-do-i-keep-getting-a-javascript-heap-out-of-memory-error) ## Answers ### General #### Is there a community to get involved with Zenbot? Of course! Check out our Reddit community ([subreddit zenbot](https://reddit.com/r/zenbot)). There is also [a shared Google Docs spreadsheet containing community sim results and variable descriptions](https://docs.google.com/spreadsheets/d/1WjFKRUY4KpkdIJiA3RVvKqiyNkMe9xtgLSfYESFXk1g/edit#gid=70204991). ### Trading #### Will I make money with Zenbot? That depends… Different configurations and strategies will yield different results. The current default config and parameters will likely lose you money, so proceed with caution. Try running simulations and paper trading first to see how the bot acts (see warning below). #### Why do simulations, paper trading, and live trading all yield different results? Simulations and paper trading almost always give overly optimistic results compared to live trading. This is because simulations and paper trading both make assumptions about when/if an order is filled. Because Zenbot defaults to using Limit orders (which often lessen fees), there tends to be much more slippage (the difference between when the bot decides to buy and when it actually buys) in live trading. Due to this, live trading is almost always worse than sims and paper trading. Also, remember that past results do not guarantee future returns. #### Why should I use simulations or paper trading if they do not reflect live trading? Simulations are more optimistic than paper trading. Paper trading is more optimistic than live trading. Therefore, if a simulation does not yield good results, odds are that neither will paper trading or (by extension) live trading. #### Does Zenbot use Limit (maker) orders or Market (taker) orders? Zenbot uses Limit orders by default because on most exchanges, Limit orders result in lower fees than Market orders. For instance, on GDAX there is no fee for a Limit order trade compared to a 0.25% (BTC) or 0.3% (ETH & LTC) trade fee on a Market order. Check your exchange for fees. ### Technical #### Can I install Zenbot on Windows? Yes, Zenbot can be installed on Windows, although it is recommended that Linux or macOS is used instead. Please note that these instructions are for Windows 10. 1. Install the "Bash on Windows subsystem" (see https://msdn.microsoft.com/en-us/commandline/wsl/about for more information) > Note: You can then choose between Ubuntu, Fedora and OpenSUSE in the Windows store. 2. Open a terminal window, your disks will now be mounted under `/mnt/*`. So for example navigate to your directory (example: `cd /mnt/c/zenbot`) 3. Install node (`curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -; sudo apt-get install nodejs`) 4. Run zenbot as you would otherwise > Note: MongoDB is not working in this subsystem, please use the Windows version! #### Is Docker necessary when installing Zenbot? No, Docker is often not necessary to run Zenbot. It is often simpler to run Zenbot on a Linux machine (Debian, CentOS, etc.) without Docker. If running Zenbot on Windows, Docker may be needed. #### How do I launch Zenbot? After installation, you lauch Zenbot via command line. Examples: ``` ./zenbot.sh backfill gdax.ETH-BTC ./zenbot.sh sim gdax.ETH-BTC --days=14 zenbot sim --days 14 ``` You can [generate a command with this shared Google Docs spreadsheet](https://docs.google.com/spreadsheets/d/1HECEHW-I9Evve_FQV3LT_IWGV6FU34tHif9TEouKtfg/edit?usp=sharing). Do not hesitate to copy this file to your Google drive or download it as an spreadsheet, as everybody can modify it simultaneously. #### How do I update Zenbot? Without Docker: ``` git pull npm install ./zenbot.sh trade --paper ``` With Docker: ``` git pull docker-compose down docker rmi zenbot_server docker-compose build docker-compose up -d ``` ### Errors #### Why do I keep getting a "Nonce" error? This error may occur when multiple instances of Zenbot are used with the same API key. To avoid this, use a different API key for each concurrent instance of Zenbot. This could also occur if the Zenbot server's time is not correct. Using NTP will keep the time current and help avoid this error. #### Why do I keep getting a "JavaScript heap out of memory" error This error may occur when your node environment does not have enough memory. Solution (Linux & Docker): Change the line `env node zenbot.js $@` in [zenbot.sh](../zenbot.sh) to `env node --max-old-space-size= zenbot.js $@` where `` is the amount of memory node is allowed to use (e.g. 4096 for 4GB). For Windows you have to change the file [zenbot.bat](../zenbot.bat) respectively. ================================================ FILE: docs/README.md ================================================ ## Quick-start ### Step 1) Requirements - Windows / Linux / macOS 10 (or Docker) - [Node.js](https://nodejs.org/) (version 8.3.0 or higher) and [MongoDB](https://www.mongodb.com/). ### Step 2) Install zenbot 4 Run in your console, ``` git clone https://github.com/deviavir/zenbot.git ``` Or, without git, ``` wget https://github.com/deviavir/zenbot/archive/master.tar.gz tar -xf master.tar.gz mv zenbot-master zenbot ``` Create your configuration file by copying `conf-sample.js` to `conf.js`: ``` cp conf-sample.js conf.js ``` - View and edit `conf.js`. - It's possible to use zenbot in "paper trading" mode without making any changes. - You must add your exchange API keys to enable real trading however. - API keys do NOT need deposit/withdrawal permissions. If using Docker, skip to section "Docker" below. Install dependencies: ``` cd zenbot npm install # optional, installs the `zenbot.sh` binary in /usr/local/bin: npm link ``` ### Ubuntu 16.04 Step-By-Step [Video](https://youtu.be/BEhU55W9pBI) [Blog Post](https://jaynagpaul.com/algorithmic-crypto-trading?utm_source=zenbot) ``` sudo apt-get update sudo apt-get upgrade -y sudo apt-get install build-essential mongodb -y curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs git clone https://github.com/deviavir/zenbot.git cd zenbot npm install ./zenbot.sh trade --paper ``` ### Docker (Optional) To run Zenbot under Docker, install Docker, Docker Compose, Docker Machine (if necessary) You can follow instructions at https://docs.docker.com/compose/install/ After installing (step 2 above), ``` cd zenbot docker-compose up (-d if you don't want to see the log) ``` If you are running windows use the following command ``` docker-compose --file=docker-compose-windows.yml up ``` If you wish to run commands (e.g. backfills, list-selectors), you can run this separate command after a successful `docker-compose up -d`: ``` docker-compose exec server zenbot list-selectors docker-compose exec server zenbot backfill --days ``` #### Updating docker In case you are behind on updates, you can run: ``` docker pull deviavir/zenbot:unstable ``` And re-run `docker-compose up -d` to start the new image. `deviavir/zenbot` is automatically updated after every merge. You can follow the tags/builds here: https://hub.docker.com/r/deviavir/zenbot/builds/ ## Selectors A "selector" is a short identifier that tells Zenbot which exchange and currency pair to act on. Use the form `{exchange_slug}.{asset}-{currency}`. A complete list of selectors your Zenbot install supports can be found with: ``` zenbot list-selectors gdax: gdax.BTC-EUR (BTC/EUR) gdax.BTC-GBP (BTC/GBP) gdax.BTC-USD (BTC/USD) gdax.ETH-BTC (ETH/BTC) gdax.ETH-USD (ETH/USD) gdax.LTC-BTC (LTC/BTC) gdax.LTC-USD (LTC/USD) poloniex: poloniex.AMP-BTC (Synereo AMP/BTC) poloniex.ARDR-BTC (Ardor/BTC) poloniex.BCN-BTC (Bytecoin/BTC) poloniex.BCN-XMR (Bytecoin/XMR) poloniex.BCY-BTC (BitCrystals/BTC) ...etc ``` ## Run a simulation for your selector To backfill data (provided that your chosen exchange supports it), use: ``` zenbot backfill --days ``` You can also select start and end date: ``` zenbot backfill --start="Unixtime in ms" --end="Unixtime in ms" ``` Note you can use them separately. After you've backfilled, you can run a simulation: ``` zenbot sim [options] ``` For a list of options for the `sim` command, use: ``` zenbot sim --help ``` For additional options related to the strategy, use: ``` zenbot list-strategies ``` - By default the sim will start with 1000 units of currency. Override with `--currency_capital` and `--asset_capital`. - Open `sim_result.html` in your browser to see a candlestick graph with trades. ### Screenshot and example result Zenbot outputs an HTML graph of each simulation result. In the screenshot below, the pink arrows represent the bot buying (up arrow) and selling (down arrow) as it iterated the historical data of [GDAX](https://gdax.com/) exchange's BTC/USD product. ![screenshot](https://cloud.githubusercontent.com/assets/106763/25983930/7e5f9436-369c-11e7-971b-ba2916442eea.png) ``` end balance 2954.50 (195.45%) buy hold 1834.44 (83.44%) vs. buy hold 61.06% 110 trades over 91 days (avg 1.21 trades/day) ``` Zenbot started with $1,000 USD and ended with $2,954.50 after 90 days, making 195% ROI! In spite of a buy/hold strategy returning a respectable 83.44%, Zenbot has considerable potential for beating buy/holders. - Note that this example used tweaked settings to achieve optimal return: `--profit_stop_enable_pct=10`, `--profit_stop_pct=4`, `--trend_ema=36`, and `--sell_rate=-0.006`. Default parameters yielded around 65% ROI. - [Raw data](https://gist.github.com/carlos8f/b09a734cf626ffb9bb3bcb1ca35f3db4) from simulation ## Running zenbot The following command will launch the bot, and if you haven't touched `c.selector` in `conf.js`, will trade the default BTC/USD pair on GDAX. ``` zenbot trade [--paper] [--manual] ``` Use the `--paper` flag to only perform simulated trades while watching the market. Use the `--manual` flag to watch the price and account balance, but do not perform trades automatically. Here's how to run a different selector (example: ETH-BTC on Poloniex): ``` zenbot trade poloniex.eth-btc ``` For a full list of options for the `trade` command, use: ``` zenbot trade --help Usage: trade [options] [selector] run trading bot against live market data Options: --conf path to optional conf overrides file --strategy strategy to use --order_type order type to use (maker/taker) --paper use paper trading mode (no real trades will take place) --manual watch price and account balance, but do not perform trades automatically --non_interactive disable keyboard inputs to the bot --currency_capital for paper trading, amount of start capital in currency --asset_capital for paper trading, amount of start capital in asset --avg_slippage_pct avg. amount of slippage to apply to paper trades --buy_pct buy with this % of currency balance --deposit absolute initial capital (in currency) at the bots disposal (previously --buy_max_amt) --sell_pct sell with this % of asset balance --markdown_buy_pct % to mark down buy price --markup_sell_pct % to mark up sell price --order_adjust_time adjust bid/ask on this interval to keep orders competitive --order_poll_time poll order status on this interval --sell_stop_pct sell if price drops below this % of bought price --buy_stop_pct buy if price surges above this % of sold price --profit_stop_enable_pct enable trailing sell stop when reaching this % profit --profit_stop_pct maintain a trailing stop this % below the high-water mark of profit --max_sell_loss_pct avoid selling at a loss pct under this float --max_buy_loss_pct avoid buying at a loss pct over this float --max_slippage_pct avoid selling at a slippage pct above this float --rsi_periods number of periods to calculate RSI at --poll_trades poll new trades at this interval in ms --currency_increment Currency increment, if different than the asset increment --keep_lookback_periods Keep this many lookback periods max. --exact_buy_orders instead of only adjusting maker buy when the price goes up, adjust it if price has changed at all --exact_sell_orders instead of only adjusting maker sell when the price goes down, adjust it if price has changed at all --use_prev_trades load and use previous trades for stop-order triggers and loss protection --min_prev_trades minimum number of previous trades to load if use_prev_trades is enabled, set to 0 to disable and use trade time instead --disable_stats disable printing order stats --reset_profit start new profit calculation from 0 --use_fee_asset Using separated asset to pay for fees. Such as binance's BNB or Huobi's HT --run_for Execute for a period of minutes then exit with status 0 (default: null) --debug output detailed debug info -h, --help output usage information ``` and also: ``` zenbot list-strategies bollinger description: Buy when (Signal ≤ Lower Bollinger Band) and sell when (Signal ≥ Upper Bollinger Band). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --bollinger_size= period size (default: 20) --bollinger_time= times of standard deviation between the upper band and the moving averages (default: 2) --bollinger_upper_bound_pct= pct the current price should be near the bollinger upper bound before we sell (default: 0) --bollinger_lower_bound_pct= pct the current price should be near the bollinger lower bound before we buy (default: 0) cci_srsi description: Stochastic CCI Strategy options: --period= period length, same as --period_length (default: 20m) --period_length= period length, same as --period (default: 20m) --min_periods= min. number of history periods (default: 30) --ema_acc= sideways threshold (0.2-0.4) (default: 0.03) --cci_periods= number of RSI periods (default: 14) --rsi_periods= number of RSI periods (default: 14) --srsi_periods= number of RSI periods (default: 9) --srsi_k= %K line (default: 5) --srsi_d= %D line (default: 3) --oversold_rsi= buy when RSI reaches or drops below this value (default: 18) --overbought_rsi= sell when RSI reaches or goes above this value (default: 85) --oversold_cci= buy when CCI reaches or drops below this value (default: -90) --overbought_cci= sell when CCI reaches or goes above this value (default: 140) --constant= constant (default: 0.015) If you have questions about this strategy, contact me... @talvasconcelos crossover_vwap description: Estimate trends by comparing "Volume Weighted Average Price" to the "Exponential Moving Average". options: --period= period length, same as --period_length (default: 120m) --period_length= period length, same as --period (default: 120m) --emalen1= Length of EMA 1 (default: 30) --smalen1= Length of SMA 1 (default: 108) --smalen2= Length of SMA 2 (default: 60) --vwap_length= Min periods for vwap to start (default: 10) --vwap_max= Max history for vwap. Increasing this makes it more sensitive to short-term changes (default: 8000) dema description: Buy when (short ema > long ema) and sell when (short ema < long ema). options: --period= period length (default: 1h) --min_periods= min. number of history periods (default: 21) --ema_short_period= number of periods for the shorter EMA (default: 10) --ema_long_period= number of periods for the longer EMA (default: 21) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 9) --overbought_rsi= sold when RSI exceeds this value (default: 80) --noise_level_pct= do not trade when short ema is with this % of last short ema, 0 disables this feature (default: 0) macd description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) momentum description: MOM = Close(Period) - Close(Length) options: --momentum_size= number of periods to look back for momentum (default: 5) neural description: Use neural learning to predict future price. Buy = mean(last 3 real prices) < mean(current & last prediction) options: --period= period length - make sure to lower your poll trades time to lower than this value. Same as --period_length (default: 1m) --period_length= period length - make sure to lower your poll trades time to lower than this value. Same as --period (default: 1m) --activation_1_type= Neuron Activation Type: sigmoid, tanh, relu (default: sigmoid) --neurons_1= Neurons in layer 1 Shoot for atleast 100 (default: 1) --depth= Rows of data to predict ahead for matches/learning (default: 1) --selector= Selector (default: Gdax.BTC-USD) --min_periods= Periods to calculate learn from (default: 1000) --min_predict= Periods to predict next number from (default: 1) --momentum= momentum of prediction (default: 0.9) --decay= decay of prediction, use teeny tiny increments (default: 0.1) --threads= Number of processing threads you'd like to run (best for sim) (default: 1) --learns= Number of times to 'learn' the neural network with past data (default: 2) noop description: Just do nothing. Can be used to e.g. for training the strategy. options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) rsi description: Attempts to buy low and sell high by tracking RSI high-water readings. options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --rsi_periods= number of RSI periods --oversold_rsi= buy when RSI reaches or drops below this value (default: 30) --overbought_rsi= sell when RSI reaches or goes above this value (default: 82) --rsi_recover= allow RSI to recover this many points before buying (default: 3) --rsi_drop= allow RSI to fall this many points before selling (default: 0) --rsi_divisor= sell when RSI reaches high-water reading divided by this value (default: 2) sar description: Parabolic SAR options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --sar_af= acceleration factor for parabolic SAR (default: 0.015) --sar_max_af= max acceleration factor for parabolic SAR (default: 0.3) speed description: Trade when % change from last two 1m periods is higher than average. options: --period= period length, same as --period_length (default: 1m) --period_length= period length, same as --period (default: 1m) --min_periods= min. number of history periods (default: 3000) --baseline_periods= lookback periods for volatility baseline (default: 3000) --trigger_factor= multiply with volatility baseline EMA to get trigger value (default: 1.6) srsi_macd description: Stochastic MACD Strategy options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) --min_periods= min. number of history periods (default: 200) --rsi_periods= number of RSI periods --srsi_periods= number of RSI periods (default: 9) --srsi_k= %D line (default: 5) --srsi_d= %D line (default: 3) --oversold_rsi= buy when RSI reaches or drops below this value (default: 20) --overbought_rsi= sell when RSI reaches or goes above this value (default: 80) --ema_short_period= number of periods for the shorter EMA (default: 24) --ema_long_period= number of periods for the longer EMA (default: 200) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) stddev description: Buy when standard deviation and mean increase, sell on mean decrease. options: --period= period length, set poll trades to 100ms, poll order 1000ms. Same as --period_length (default: 100ms) --period_length= period length, set poll trades to 100ms, poll order 1000ms. Same as --period (default: 100ms) --trendtrades_1= Trades for array 1 to be subtracted stddev and mean from (default: 5) --trendtrades_2= Trades for array 2 to be calculated stddev and mean from (default: 53) --min_periods= min_periods (default: 1250) ta_ema description: Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI. options: --period= period length, same as --period_length (default: 10m) --period_length= period length, same as --period (default: 10m) --min_periods= min. number of history periods (default: 52) --trend_ema= number of periods for trend EMA (default: 20) --neutral_rate= avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter) (default: 0.06) --oversold_rsi_periods= number of periods for oversold RSI (default: 20) --oversold_rsi= buy when RSI reaches this value (default: 30) ta_macd description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_macd_ext description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0) with controllable talib TA types options: --period= period length, same as --period_length (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --fast_ma_type= fast_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --slow_ma_type= slow_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --signal_ma_type= signal_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --default_ma_type= set default ma_type for fast, slow and signal. You are able to overwrite single types separately (fast_ma_type, slow_ma_type, signal_ma_type) (default: SMA) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_trix description: TRIX - 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA with rsi oversold options: --period= period length eg 10m (default: 5m) --timeperiod= timeperiod for TRIX (default: 30) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) trend_ema (default) description: Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI. options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --trend_ema= number of periods for trend EMA (default: 26) --neutral_rate= avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter) (default: auto) --oversold_rsi_periods= number of periods for oversold RSI (default: 14) --oversold_rsi= buy when RSI reaches this value (default: 10) ta_ppo description: PPO - Percentage Price Oscillator with rsi oversold options: --period= period length, same as --period_length (default: 10m) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --ma_type== moving average type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: SMA) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_ultosc description: ULTOSC - Ultimate Oscillator with rsi oversold options: --period= period length eg 5m (default: 5m) --min_periods= min. number of history periods (default: 52) --signal= Provide signal and indicator "simple" (buy@65, sell@50), "low" (buy@65, sell@30), "trend" (buy@30, sell@70) (default: simple) --timeperiod1= talib ULTOSC timeperiod1 (default: 7) --timeperiod2= talib ULTOSC timeperiod2 (default: 14) --timeperiod3= talib ULTOSC timeperiod3 (default: 28) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 90) ti_hma description: HMA - Hull Moving Average options: --period= period length eg 10m (default: 15m) --min_periods= min. number of history periods (default: 52) --trend_hma= number of periods for trend hma (default: 36) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) trendline description: Calculate a trendline and trade when trend is positive vs negative. options: --period= period length (default: 30s) --period_length= period length (default: 30s) --lastpoints= Number of trades for short trend average (default: 100) --avgpoints= Number of trades for long trend average (default: 1000) --lastpoints2= Number of trades for short trend average (default: 10) --avgpoints2= Number of trades for long trend average (default: 100) --min_periods= Basically avgpoints + a BUNCH of more preroll periods for anything less than 5s period (default: 15000) --markup_sell_pct= test (default: 0) --markdown_buy_pct= test (default: 0) trust_distrust description: Sell when price higher than $sell_min% and highest point - $sell_threshold% is reached. Buy when lowest price point + $buy_threshold% reached. options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) --min_periods= min. number of history periods (default: 52) --sell_threshold= sell when the top drops at least below this percentage (default: 2) --sell_threshold_max= sell when the top drops lower than this max, regardless of sell_min (panic sell, 0 to disable) (default: 0) --sell_min= do not act on anything unless the price is this percentage above the original price (default: 1) --buy_threshold= buy when the bottom increased at least above this percentage (default: 2) --buy_threshold_max= wait for multiple buy signals before buying (kill whipsaw, 0 to disable) (default: 0) --greed= sell if we reach this much profit (0 to be greedy and either win or lose) (default: 0) wavetrend description: Buy when (Signal < Oversold) and sell when (Signal > Overbought). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 21) --wavetrend_channel_length= wavetrend channel length (default: 10) --wavetrend_average_length= wavetrend average length (default: 21) --wavetrend_overbought_1= wavetrend overbought limit 1 (default: 60) --wavetrend_overbought_2= wavetrend overbought limit 2 (default: 53) --wavetrend_oversold_1= wavetrend oversold limit 1 (default: -60) --wavetrend_oversold_2= wavetrend oversold limit 2 (default: -53) --wavetrend_trends= act on trends instead of limits (default: false) --overbought_rsi_periods= number of periods for overbought RSI (default: 9) --overbought_rsi= sold when RSI exceeds this value (default: 80) ``` ## Interactive controls While the `trade` command is running, Zenbot will respond to these keypress commands: - Pressing `b` will trigger a buy, `s` for sell, and `B` and `S` for market (taker) orders. - Pressing `c` or `C` will cancel any active orders. - Pressing `m` or `M` will toggle manual mode (`--manual`) These commands can be used to override what the bot is doing. Or, while running with the `--manual` flag, this allows you to make all the trade decisions yourself. ### noop strategy If you want to use the bot without it trading for you, but just use it for the balance overview and manual trades, you can start the bot with `--strategy noop`, the bot will not trade automatically. ## Conf/argument override files To run `trade` or `sim` commands with a pre-defined set of options, use: ``` zenbot trade --conf ``` Where `` points to a JS file that exports an object hash that overrides any conf or argument variables. For example, this file will run gdax.ETH-USD with options specific for that market: ``` var c = module.exports = {} // ETH settings (note: this is just an example, not necessarily recommended) c.selector = 'gdax.ETH-USD' c.period = '10m' c.trend_ema = 20 c.neutral_rate = 0.1 c.oversold_rsi_periods = 20 c.max_slippage_pct = 10 c.order_adjust_time = 10000 ``` ## GUI A basic web UI is available at the url stated during startup. This port can be configured in the conf.js or randomly assigned. In it's infancy, there are a few caveats with the current UI. - In order to have statistics displayed, they must first be dumped from the CLI. Pressing `D` will refresh the statistics on each refresh of the dashboard. - Currently the data is mostly static with the exception of the tradingview charts. - Currently only READ-ONLY ## Reading the console output ![console](https://rawgit.com/deviavir/zenbot/master/assets/console.png) From left to right: - Timestamp in local time (grey, blue when showing "live" stats) - Asset price in currency (yellow) - Percent change of price since last period (red/green) - Volume in asset since last period (grey) - [RSI](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi) ANSI graph (red/green) - `trend_ema_rate` (red/green, explained below) - Current signal or action, including `buy`, `sell`, `buying`, `selling`, `bought`, `sold` and `last_trade_worth` (percent change in the trend direction since last buy/sell) - Account balance (asset) - Account balance (currency) - Profit or loss percent (can be reset with `--reset_profit`) - Gain or loss vs. buy/hold strategy ## Strategies ### The `trend_ema` strategy (default) - The default strategy is called `trend_ema` and resides at `./extensions/strategies/trend_ema`. - Defaults to using a 2m period, but you can override this with adding e.g. `--period=5m` to the `sim` or `trade` commands. - Computes the 26-period EMA of the current price, and calculates the percent change from the last period's EMA to get the `trend_ema_rate` - Considers `trend_ema_rate >= 0` an upwards trend and `trend_ema_rate < 0` a downwards trend - Filters out low values (whipsaws) by `neutral_rate`, which when set to `auto`, uses the standard deviation of the `trend_ema_rate` as a variable noise filter. - Buys at the beginning of upwards trend, sells at the beginning of downwards trend - If `oversold_rsi` is set, tries to buy when the RSI dips below that value, and then starts to recover (a counterpart to `--profit_stop_enable_pct`, which sells when a percent of profit is reached, and then dips) - The bot will always try to avoid trade fees, by using post-only orders and thus being a market "maker" instead of a "taker". Some exchanges will, however, not offer maker discounts. ### The `macd` strategy The moving average convergence divergence calculation is a lagging indicator, used to follow trends. - Can be very effective for trading periods of 1h, with a shorter period like 15m it seems too erratic and the Moving Averages are kind of lost. - It's not firing multiple 'buy' or 'sold' signals, only one per trend, which seems to lead to a better quality trading scheme. - Especially when the bot will enter in the middle of a trend, it avoids buying unless it's the beginning of the trend. ### The `rsi` strategy Attempts to buy low and sell high by tracking RSI high-water readings. - Effective in sideways markets or markets that tend to recover after price drops. - Risky to use in bear markets, since the algorithm depends on price recovery. - If the other strategies are losing you money, this strategy may perform better, since it basically "reverses the signals" and anticipates a reversal instead of expecting the trend to continue. ### The `sar` strategy Uses a [Parabolic SAR](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:parabolic_sar) indicator to trade when SAR trend reverses. - Tends to generate earlier signals than EMA-based strategies, resulting in better capture of highs and lows, and better protection against quick price drops. - Does not perform well in sideways (non-trending) markets, generating more whipsaws than EMA-based strategies. - Most effective with short period (default is 2m), which means it generates 50-100 trades/day, so only usable on GDAX (with 0% maker fee) at the moment. - Tested live, [results here](https://github.com/carlos8f/zenbot/pull/246#issuecomment-307528347) ### The `speed` strategy Trade when % change from last two 1m periods is higher than average. **This strategy is experimental and has WILDLY varying sim results. NOT RECOMMENDED YET.** - Like the sar strategy, this generates early signals and can be effective in volatile markets and for sudden price drop protection. - Its weakness is that it performs very poorly in low-volatility situations and misses signals from gradually developing trends. ### Tips for tweaking options - Trade frequency is adjusted with a combination of `--period` and `--trend_ema`. For example, if you want more frequent trading, try `--period=5m` or `--trend_ema=15` or both. If you get too many ping-pong trades or losses from fees, try increasing `period` or `trend_ema` or increasing `neutral_rate`. - Sometimes it's tempting to tell the bot trade very often. Try to resist this urge, and go for quality over quantity, since each trade comes with a decent amount of slippage and whipsaw risk. - `--oversold_rsi=` will try to buy when the price dives. This is one of the ways to get profit above buy/hold, but setting it too high might result in a loss if the price continues to fall. - In a market with predictable price surges and corrections, `--profit_stop_enable_pct=10` will try to sell when the last buy hits 10% profit and then drops to 9% (the drop % is set with `--profit_stop_pct`). However in strong, long uptrends this option may end up causing a sell too early. - For Kraken and GDAX you may wish to use `--order_type="taker"`, this uses market orders instead of limit orders. You usually pay a higher fee, but you can be sure that your order is filled instantly. This means that the sim will more closely match your live trading. Please note that GDAX does not charge maker fees (limit orders), so you will need to choose between not paying fees and running the risk orders do not get filled on time, or paying somewhat high % of fees and making sure your orders are always filled on time. ## Notifiers Zenbot employs various notifiers to keep you up to date on the bot's actions. We currently send a notification on a buy and on a sell signal. ### pushbullet Supply zenbot with your api key and device ID and we will send your notifications to your device. https://www.pushbullet.com/ ### Slack Supply zenbot with a webhook URI and zenbot will push notifications to your webhook. https://slack.com/ ### XMPP Supply zenbot with your XMPP credentials and zenbot will send notifications by connecting to your XMPP, sending the notification, and disconnecting. https://xmpp.org/ ### IFTTT Supply zenbot with your IFTTT maker key and zenbot will push notifications to your IFTTT. https://ifttt.com/maker_webhooks ### DISCORD Supply zenbot with your Discord webhook id and webhook token zenbot will push notifications to your Discord channel. How to add a webhook to a Discord channel https://support.discordapp.com/hc/en-us/articles/228383668 ### Prowl Supply zenbot with your Prowl API key and zenbot will push notifications to your Prowl enabled devices. https://www.prowlapp.com/ ### TextBelt Supply zenbot with your TextBelt API key and zenbot will send SMS notifications to your cell phone. https://www.textbelt.com/ ### Telegram Supply zenbot with your Telegram bot token and chat id zenbot will push notifications to your Telegram chat. https://telegram.org/ ### ADAMANT Messenger Supply Zenbot with recipients' ADM addresses, sender's account passPhrase and node list and Zenbot will push notifications to ADAMANT chats. https://adamant.im/ ## Rest API You can enable a Rest API for Zenbot by enabling the following configuration ``` c.output.api = {} c.output.api.on = true c.output.api.port = 0 // 0 = random port ``` You can choose a port, or pick 0 for a random port. Once you did that, you can call the API on: http://\:\/trades ## Manual trade tools Zenbot's order execution engine can also be used for manual trades. Benefits include: - Avoids market-order fees by using a short-term limit order - Can automatically determine order size from account balance - Adjusts order every 30s (if needed) to ensure quick execution - If an order is partially filled, attempts to re-order with remaining size The command to buy is: ``` zenbot buy [--size=] [--pct=] ``` For example, to use your remaining USD balance in GDAX to buy Bitcoin: ``` zenbot buy gdax.BTC-USD ``` Or to sell 10% of your BTC, ``` zenbot sell gdax.BTC-USD --pct=10 ``` ================================================ FILE: docs/developers.md ================================================ ## Zenbot exchange API This document is written to help developers implement new extensions for Zenbot. It is reverse engineered from inspecting the Zenbot files and the GDAX extension and is not a definitive guide for developing an extension. Any contribution that makes this document better is certainly welcome. The document is an attempt to describe the interface functions used for communication with an exchange and a few helper functions. Each function has a set of calling parameters and return values and statuses The input parameters are packed in the "opts" object, and the results from invoking the function are returned in an object. ## Error handling Errors are returned to calling program through a callback functon of this form: ```javascript cb (err) ``` The expected content of "err" is as follows: ```javascript { code: 'HTTP_STATUS', body: body } ``` **Non recoverable errors** should be handled by the actual extension function. A typical error is "Page not found", which most likely is caused by a malformed URL. Such errors should return a descriptive message and force a program exit. **Recoverable errors** affecting trades should be handled by zenbot, while others could be handled in the extension layer. This needs to be clarified. Some named errors are already handled by the main program (see getTrades below). These are: ``` 'ETIMEDOUT', // possibly recoverable 'ENOTFOUND', // not recoverable (404?) 'ECONNRESET' // possibly recoverable ``` Zenbot may have some GDAX-specific code. In particular that pertains to return values from exchange functions. Return values in general should be handled in a exchange agnostic and standardized way to make it easiest possible to write extensions. **Some variables in the "exchange" object are worth mentioning** ``` name: 'some_exchange_name' historyScan: 'forward', 'backward' or false makerFee: exchange_maker_fee (numeric) // Set by a function if the exchange supports it takerFee: exchange_taker_fee (numeric) // Else set with a constant backfillRateLimit: some_value_fitting_exchange_policy or 0 ``` ## Functions **Connecting to the exchange for public requests** ```javascript funcion publicClient () ``` Called from: - extension/*/exchange.js Returns a "client" object for use in exchange public access functions. **Connecting and authenticating private requests** ```javascript function authedClient () ``` Called from: - extension/*/exchange.js The function gets parameters from conf.js in the c object In particular these are: ``` c..key c..secret ``` For specific exchanges also: ``` c.bitstamp.client_id c.gdax.passphrase ``` The functionm returns a "client" object for use in exchange authenticated access functions **Helper function for returning conformant error messages** ```javascript function statusErr (resp, body) ``` Called from: - extension/*/exchange.js **Getting public history and trade data** ```javascript getTrades: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/commands/backfill.js - https://github.com/carlos8f/zenbot/blob/master/commands/trade.js Input: ``` opts.product_id opts.from opts.to ``` Return: ``` trades.length (array of?) { trade_id: some_id time: 'transaction_time', size: trade_size, price: trade_prize, side : 'buy' or 'sell' } ``` Expected error codes if error: ``` err.code 'ETIMEDOUT', // possibly recoverable 'ENOTFOUND', // not recoverable 'ECONNRESET' // possibly recoverable ``` Callback: ```javascript cb(null, trades) ``` **Getting wallet balances** ```javascript getBalance: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js Input: ``` opts.currency opts.asset ``` Return: ``` balance.asset balance.asset_hold balance.currency balance.currency_hold ``` Callback: ```javascript cb(null, balance) ``` Comment: Asset vs asset_hold and currency vs currency_hold is kind of mysterious to me. For most exchanges I would just return something similar to available_asset and available_currency For exchanges that returns some other values, I would do the calculation on the extension layer and not leave it to engine.js, because available_asset and available_currency are only interesting values from a buy/sell view, IMHO. If someone knows better, please clarify **Getting public ticker data** ```javascript getQuote: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js - https://github.com/carlos8f/zenbot/blob/master/commands/buy.js - https://github.com/carlos8f/zenbot/blob/master/commands/sell.js Input: ``` opts.product_id ``` Return: ``` {bid: value_of_bid, ask: value_of_ask} ``` Callback: ```javascript cb(null, {bid: body.bid, ask: body.ask}) ``` **Canceling a placed order** ```javascript cancelOrder: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js Input: ``` opts.order_id ``` Callback: ```javascript cb() ``` **Buying function** ```javascript buy: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js Input: ``` opts.price opts.size ``` Returns: ``` ``` Callback: ```javascript cb(null, body) ``` **Selling function** ```javascript sell: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js Input: ``` opts.price opts.size ``` Returns: ``` ``` Callback: ```javascript cb(null, body) ``` **Getting data from a placed order** ```javascript getOrder: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js Input: ``` opts.order_id opts.product_id ``` Returns: ``` order.status ``` Expected values in https://github.com/carlos8f/zenbot/blob/master/lib/engine.js: - 'done', 'rejected' If 'rejected' order.reject_reason = some_reason ('post only') Is '*post only*' spesific for GDAX? Comment: Needs some clarifying Callback: ```javascript cb(null, body) ``` **Getting details from an executed trade** ```javascript getCursor: function (trade) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/commands/backfill.js - https://github.com/carlos8f/zenbot/blob/master/commands/trade.js Input: ``` trade - This is either a trade or a timestamp ``` Return: ``` trade id or timestamp. It really depends on the exchange API. Some, like Gemini, use only timestamps and will only need to return a timestamp. Others, like GDAX operate on trade ids and it is expected to return 'undefined' when passed an initial timestamp to start backfilling. Since backfilling requires a timestamp to select the numbers of days to backfill, it may not be possible to use this option if the exchange does not use timestamps for historical data. In this case return 'undefined' when passed a timestamp value. ``` Callback: ```javascript ``` ## Extensions Zenbot offers various extensions, arguably it is what makes zenbot so awesome. ### Extending notifiers If you wish to add a new notifier, please follow these steps: - create a your-service-name.js in `/extensions/notifiers/` make sure to use the same function returns as other notifiers - add config bootstrap to `/conf-sample.js` - send us a PR with your new service :) ================================================ FILE: docs/exchanges/bitstamp.md ================================================ # Zenbot Tips for Bitstamp The following tips can increase reliability in using Zenbot with Bitstamp. ## 0 Balance This is often an indication of a mistake in your conf `c.bitstamp.client_id` value. This value should be set to the value of your Customer ID. You can find this ID by going to My Account in Bitstamp: https://www.bitstamp.net/account/balance/ ================================================ FILE: docs/exchanges/gdax.md ================================================ # Zenbot Tips for GDAX The following tips can increase reliability in using Zenbot with GDAX (Coinbase Pro). ## Sandbox A public sandbox is available for testing API connectivity and web trading. While the sandbox only hosts a subset of the production order books, all of the exchange functionality is available. Additionally, in this environment you are allowed to add unlimited fake funds for testing. Adjust the config file to enable (true) or disable (false) the use of the sandbox. Ensure the correct API credentials (live or sandbox) are inputted in the config file - otherwise you will recieve an API error. Additionally you will not use the --paper option since it will be conducting (simulated) trades in the sandbox. The default setting is set to false. Example of the Sandbox enabled: ``` c.gdax.sandbox = process.env.ZENBOT_GDAX_SANDBOX || true ``` ## Fee Limits GDAX (Coinbase Pro) uses a maker-taker fee model for determining its trading fees. Orders that provide liquidity (maker orders) are charged different fees than orders that take liquidity (taker orders). Fees are calculated based on the current pricing tier you are in when the order is placed, and not on the tier you would be in after a trade is completed. See your GDAX (Coinbase Pro) fees here - https://pro.coinbase.com/orders/fees. To adjust the fee limits to match your current pricing tier, modifiy the following javascript file. ``` extensions/exchanges/gdax/exchange.js ``` Look for this line: ``` var exchange = { name: 'gdax', historyScan: 'backward', makerFee: 0.35, takerFee: 0.35, backfillRateLimit: 335, ``` Adjust the makerFee and takerFee, for example: ``` var exchange = { name: 'gdax', historyScan: 'backward', makerFee: 0.5, takerFee: 0.5, backfillRateLimit: 335, ``` ================================================ FILE: docs/exchanges/kraken.md ================================================ # Zenbot Tips for Kraken The following tips can increase reliability in using Zenbot with Kraken. ## API Rate Limit These errors mean that Zenbot is sending too many requests to Kraken in a given amount of time: > Kraken API error - unable to call getTrades (Error: Kraken API returned error: API:Rate limit exceeded), retrying in There are two ways past this: * Increase your [Kraken Account Tier](https://support.kraken.com/hc/en-us/articles/206548367-What-is-the-API-call-rate-limit-). Higher tier accounts have a more relaxed rate limit. * Increase poll timers in the zenbot `conf.js`. This reduces how many requests Zenbot is sending in a given amount of time. ### Poll Timers The following `conf.js` settings have helped prevent this from happening: ```javascript // Poll order status every 3 seconds c.order_poll_time = 3000 // Poll new trades every 6 seconds c.poll_trades = 6000 ``` ## Kraken API returned error: API:Invalid nonce This is a common error when calling exchange APIs on a regular basis: >Kraken API warning - unable to call getBalance (Error: Kraken API returned error: API:Invalid nonce), retrying in 0.15s Nonce errors aren't usually an issue but can introduce a slight delay in your trading. In Kraken, you can increase your API Nonce window, reducing the chances of this happening. Log into your Kraken account, navigate through *Settings* then *API*, select your API Key and increase your *Nonce Window* for the API Key used by Zenbot. ## Orders Placed & Forgotten I've seen Zenbot getting stuck with `Selling` or `Buying`. Checking for open orders in Kraken, I see the open order there, but Zenbot doesn't seem to have realised the order was placed. This usually happens while the Kraken API is under high load. The solution to this is a simple change in this javascript file: ``` node_modules/kraken-api/kraken.js ``` Look for this line: ``` var config = { url: 'https://api.kraken.com', version: '0', key: key, secret: secret, otp: otp, timeoutMS: 5000 }; ``` Increase the timeoutMS value, for example: ``` var config = { url: 'https://api.kraken.com', version: '0', key: key, secret: secret, otp: otp, timeoutMS: 30000 }; ``` ================================================ FILE: docs/exchanges/readme.md ================================================ # Zenbot Exchange API Tips Since Zenbot supports a number of exchanges, it's becoming harder to provide "default" polling settings that work well with all exchange APIs. The goal of this document is to share any settings or tweaks that we find to increase reliability. Anything from proventing API rate limit lockouts (GDAX) to ensuring orders are tracked properly (Kraken). Any contribution that makes this better for everyone is certainly welcome. ## Exchanges * [Bitstamp](bitstamp.md) * [GDAX](gdax.md) * [Kraken](kraken.md) ================================================ FILE: docs/installation/README.md ================================================ ### Install Zenbot Run in your console: ``` git clone https://github.com/deviavir/zenbot.git ``` Or, without git: ``` wget https://github.com/deviavir/zenbot/archive/master.tar.gz tar -xf zenbot-master.tar.gz mv zenbot-master zenbot ``` Create your configuration file by copying `conf-sample.js` to `conf.js`: ``` cp conf-sample.js conf.js ``` - View and edit `conf.js`. - It's possible to use Zenbot in "paper trading" mode without making any changes. - You must add your exchange API keys to enable real trading however. - API keys do **not** need deposit/withdrawal permissions. If using Docker, skip to the [Docker guide](docker.md). Install dependencies: ``` cd zenbot npm install ``` Optional: Install the `zenbot.sh` binary in `/usr/local/bin`: ``` npm link ``` Run a Zenbot command: ``` zenbot --help ``` ================================================ FILE: docs/installation/debian-ubuntu.md ================================================ #### Debian-based OSes (complete guide) Although this guide was initially created for Ubuntu 20.04, Also works with Debian. ``` sudo apt-get install curl python2 git build-essential mongodb nodejs curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash - sudo apt-get update sudo apt-get upgrade -y sudo apt-get install curl python2 git build-essential mongodb nodejs git clone https://github.com/deviavir/zenbot.git cd zenbot npm install ./zenbot.sh --help ``` [Blog Post (Ubuntu 16.04)](https://jaynagpaul.com/algorithmic-crypto-trading?utm_source=zenbot) [Video (Ubuntu 16.04)](https://youtu.be/BEhU55W9pBI) ================================================ FILE: docs/installation/docker.md ================================================ #### Using Docker To run Zenbot under Docker, install Docker, Docker Compose, Docker Machine (if necessary). You can follow instructions at https://docs.docker.com/compose/install/. After [installing Zenbot](README.md): ``` cd zenbot docker-compose up # -d if you don't want to see the log ``` If you are running Windows use the following command: ``` docker-compose --file=docker-compose-windows.yml up ``` If you wish to run commands (e.g. backfills, list-selectors), you can run this separate command after a successful `docker-compose up -d`: ``` docker-compose exec server zenbot list-selectors docker-compose exec server zenbot backfill --days ``` #### Updating Docker In case you are behind on updates, you can run: ``` docker pull deviavir/zenbot:unstable ``` And re-run `docker-compose up -d` to start the new image. `deviavir/zenbot` is automatically updated after every merge. You can follow the tags/builds at https://hub.docker.com/r/deviavir/zenbot/builds/. ================================================ FILE: docs/installation/raspberrypi.md ================================================ #### Raspberry Pi You can run Zenbot on a Raspberry Pi and the default Raspbian OS, but it is not recommend because MongoDB has problems with ARM systems as well as 32-bit OSes since it limits the database to 2GB. Make sure packages are updated: ``` sudo apt-get update sudo apt-get upgrade -y ``` Install Docker: ``` curl -sSL https://get.docker.com | sh ``` Autostart on startup: ``` sudo systemctl enable docker ``` Give user permissions: ``` sudo usermod -aG docker ``` Reboot, or execute `sudo systemctl start docker`. Install docker-compose: ``` apt-get install python-pip pip install docker-compose ``` Install a MongoDB Docker image made for the Rapsberry Pi (like https://hub.docker.com/r/nonoroazoro/rpi-mongo/): ``` docker pull nonoroazoro/rpi-mongo ``` Rename the MongoDB docker-file to "mongo" (if you use the above image): ``` docker tag nonoroazoro/rpi-mongo mongo ``` Install Zenbot, described in the [installation guide](README.md). Run Zenbot: ``` cd zenbot docker-compose build docker-compose up -d ``` Commands are the same: ``` docker run --rm --link zenbot_mongodb_1:mongodb -it zenbot_server [command] ``` ================================================ FILE: docs/installation/requirements.md ================================================ ### Requirements The only requirements to install and run Zenbot are - Linux / macOS 10 / Windows (or Docker) - [Node.js](https://nodejs.org/) (version 8.3.0 or higher) - [MongoDB](https://www.mongodb.com/) #### Recommendations - It is recommend to use a 64-bit processor (and OS), because a 32-bit OS will limit the database to 2GB. ================================================ FILE: docs/notifiers/README.md ================================================ ## Notifiers Zenbot employs various notifiers to keep you up to date on the bot's actions. We currently send a notification on a buy and on a sell signal. ### XMPP Supply Zenbot with your XMPP credentials and Zenbot will send notifications by connecting to your XMPP, sending the notification, and disconnecting. https://xmpp.org/ ### Pushbullet Supply Zenbot with your API key and device ID and Zenbot will send notifications to your device. https://www.pushbullet.com/ ### IFTTT Supply Zenbot with your IFTTT maker key and Zenbot will push notifications to your IFTTT. https://ifttt.com/maker_webhooks ### Slack Supply Zenbot with a webhook URI and Zenbot will push notifications to your webhook. https://slack.com/ ### Discord Supply Zenbot with your Discord webhook id and webhook token and Zenbot will push notifications to your Discord channel. How to add a webhook to a Discord channel https://support.discordapp.com/hc/en-us/articles/228383668 ### Prowl Supply Zenbot with your Prowl API key and Zenbot will push notifications to your Prowl enabled devices. https://www.prowlapp.com/ ### Textbelt Supply Zenbot with your Textbelt API key and Zenbot will send SMS notifications to your cell phone. https://www.textbelt.com/ ### Pushover Supply Zenbot with your api token and user key and Zenbot will send notifications to your device. https://pushover.net/ ### Telegram Supply Zenbot with your Telegram bot token and chat id and Zenbot will push notifications to your Telegram chat. https://telegram.org/ ### ADAMANT Messenger Supply Zenbot with recipients' ADM addresses, sender's account passPhrase and node list and Zenbot will push notifications to ADAMANT chats. https://adamant.im/ ================================================ FILE: docs/scripts/genetic_backtester.md ================================================ # Genetic Backtester - Darwin The Genetic Backtester will execute a range of simulations with a range of parameters, limited by the population size, per strategy. Once all sims in the population are complete, the top results are taken as the starting point for the next generation. This continues indefinitely, until interrupted by the user, or --runGenerations is reached. ## Installation This script has additional node dependencies that need to be installed before usage: ```bash cd scripts/genetic_backtester npm install cd ../../ ``` ## Usage Launch the genetic backtester from the zenbot root by directly invoking darwin.js: ```bash ./scripts/genetic_backtester/darwin.js --selector="bitfinex.ETH-USD" --days="10" --currency_capital="1000" --use_strategies="all | macd,trend_ema,etc" --population="101" --population_data="simulations/generation_data_[simtimestamp]_gen_[x].json" ``` ## Parameters The following parameters are available when executing darwin.js: ``` // General Parameters --selector="gdax.BTC-USD" # Which selector (exchange.COIN-ALT) backfill trade data the backtest is to be run against. --days="30" # How many days of backfill to run the backtest against. (or) --start="201712010001" # Specifies date/time in "YYYYMMDDhhmm" format at which to begin backtesting in liu of --days. Backtest will begin with start date through backtest execution time. --end="201712312359" # Optional - Used in conjunction with --start in order to restrict backtesting to a specific period instead of from start -> now. --currency_capital="1000" # Currency amount to start simulations with. Needs to be bigger than 0 (see issue #449). (or) --asset_capital="100" # Optional - Asset amount to start simulations with. // Specific Parameters --use_strategies="all | strategy1,strategy2" # With this parameter, you can choose to test all, some (comma separated), or just one of the available strategies defined within darwin. --population="150" # Optional - Number of simulation per generation --population_data="./simulations/backtest_[simtimestamp]" # Optional - Resume backtesting on a previously terminated backtesting session. --runGenerations # Optional - Makes it possible to stop after a number of generations ``` ## Results When the next generation starts testing, a csv file will appear in the simulations folder. This CSV contains all simulations that were executed in that generation, including the parameters and results. The top results are listed at the top of the file, in descending order. ## Further Customization The default ranges can be further customized per strategy by editing the [darwin.js](blob/master/scripts/genetic_backtester/darwin.js) script. ================================================ FILE: docs/scripts/readme.md ================================================ # Scripts In the scripts folder are a number of helper scripts. This is the corresponding documentation so far, with more information on each set of scripts: * [auto_backtester](auto_backtester.md) *not done yet, contributions welcome* * [genetic_algo](genetic_algo.md) *not done yet, contributions welcome* * [Genetic Backtester](genetic_backtester.md) ================================================ FILE: docs/strategies/howto_create_strategy.md ================================================ # How to create a strategy? Are you sure? At least you should have a minimum of code-writing skills... **You can find help and very useful information here:** https://www.reddit.com/r/zenbot/ https://discord.gg/z2VyhmxP8P First of all, you are advised to read the base zenbot documentation, that can be found [here](https://github.com/DeviaVir/zenbot/tree/unstable/docs "here"). ## # How Zenbot works with strategies? Zenbot load a strategy by finding the file extensions/strategies/``/strategy.js ## # What to do? ### ## 1. Create a new strategy file You should create a new folder inside strategies folder and name it whatever you want. You also can create a copy of the ..\extensions\strategies\noop folder and rename it. NOOP strategy is just an example of a strategy file. You should have NOOP folder inside strategies folder but if you dont have it, you can download it here: https://github.com/DeviaVir/zenbot/tree/unstable/extensions/strategies This is what you probably will find inside the NOOP strategy file: module.exports = { name: 'noop', description: 'Just do nothing. Can be used to e.g. for training the strategy.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') }, calculate: function () { }, onPeriod: function (s, cb) { cb() }, onReport: function () { var cols = [] return cols } } ## # How strategy file is organized? Zenbot strategy file is organized in 4 sections: - getOptions - calculate - onPeriod - onReport ## getOptions Zenbot will search where the variables needed for your strategy. getOptions: function (s) { this.option('period', 'period length, same as --period_length', String, '5m') this.option('period_length', 'period length, same as --period', String, '5m') this.option('min_periods', 'min. number of history periods', Number, 200) // insert here the variables that your strategy will use. ** } ## calculate It's called each time there is a new trade. it's the right place to update indicators. // calculate MACD ema(s, 'ema_short', s.options.ema_short_period) ema(s, 'ema_long', s.options.ema_long_period) if (s.period.ema_short && s.period.ema_long) { s.period.macd = (s.period.ema_short - s.period.ema_long) ema(s, 'signal', s.options.signal_period, 'macd') if (s.period.signal) { s.period.macd_histogram = s.period.macd - s.period.signal } Or if you simply want to use RSI indicator: // RSI indicator rsi(s, 'rsi', s.options.rsi_periods) ## onPeriod It's called at the end of each period. It will be the right place to send 'buy' or 'sell' signals. For example if you want to buy or sell based on RSI indicator: if (s.period.rsi < 30) { s.signal = 'buy' } ## onReport called each time the console is refreshed. It must return an array, and each item in this array will be displayed in the console (after the RSI and before the balance). Example: onReport: function (s) { var cols = [] if (typeof s.period.rsi === 'number') { var color = 'grey' if (s.period.rsi <= s.options.oversold_rsi) { color = 'green' } if (s.period.rsi >= s.options.overbought_rsi) { color = 'red' } cols.push(z(4, n(s.period.rsi).format('0'), ' ')[color]) } return cols }, ## # How can I look for past values? ## Lookback Each time the period change, the current period is put at the beginning of `s.lookback` and `s.period` is reset. So you can check the last period in `s.lookback[0]`, the one before in `s.lookback[1]`, and so on. ### Thanks to: - BAKfr - TxTheNoob ================================================ FILE: docs/strategies/list-strategies.md ================================================ ``` zenbot list-strategies bollinger description: Buy when (Signal ≤ Lower Bollinger Band) and sell when (Signal ≥ Upper Bollinger Band). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --bollinger_size= period size (default: 20) --bollinger_time= times of standard deviation between the upper band and the moving averages (default: 2) --bollinger_upper_bound_pct= pct the current price should be near the bollinger upper bound before we sell (default: 0) --bollinger_lower_bound_pct= pct the current price should be near the bollinger lower bound before we buy (default: 0) cci_srsi description: Stochastic CCI Strategy options: --period= period length, same as --period_length (default: 20m) --period_length= period length, same as --period (default: 20m) --min_periods= min. number of history periods (default: 30) --ema_acc= sideways threshold (0.2-0.4) (default: 0.03) --cci_periods= number of RSI periods (default: 14) --rsi_periods= number of RSI periods (default: 14) --srsi_periods= number of RSI periods (default: 9) --srsi_k= %K line (default: 5) --srsi_d= %D line (default: 3) --oversold_rsi= buy when RSI reaches or drops below this value (default: 18) --overbought_rsi= sell when RSI reaches or goes above this value (default: 85) --oversold_cci= buy when CCI reaches or drops below this value (default: -90) --overbought_cci= sell when CCI reaches or goes above this value (default: 140) --constant= constant (default: 0.015) If you have questions about this strategy, contact me... @talvasconcelos crossover_vwap description: Estimate trends by comparing "Volume Weighted Average Price" to the "Exponential Moving Average". options: --period= period length, same as --period_length (default: 120m) --period_length= period length, same as --period (default: 120m) --emalen1= Length of EMA 1 (default: 30) --smalen1= Length of SMA 1 (default: 108) --smalen2= Length of SMA 2 (default: 60) --vwap_length= Min periods for vwap to start (default: 10) --vwap_max= Max history for vwap. Increasing this makes it more sensitive to short-term changes (default: 8000) dema description: Buy when (short ema > long ema) and sell when (short ema < long ema). options: --period= period length (default: 1h) --min_periods= min. number of history periods (default: 21) --ema_short_period= number of periods for the shorter EMA (default: 10) --ema_long_period= number of periods for the longer EMA (default: 21) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 9) --overbought_rsi= sold when RSI exceeds this value (default: 80) --noise_level_pct= do not trade when short ema is with this % of last short ema, 0 disables this feature (default: 0) macd description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) momentum description: MOM = Close(Period) - Close(Length) options: --momentum_size= number of periods to look back for momentum (default: 5) neural description: Use neural learning to predict future price. Buy = mean(last 3 real prices) < mean(current & last prediction) options: --period= period length - make sure to lower your poll trades time to lower than this value. Same as --period_length (default: 1m) --period_length= period length - make sure to lower your poll trades time to lower than this value. Same as --period (default: 1m) --activation_1_type= Neuron Activation Type: sigmoid, tanh, relu (default: sigmoid) --neurons_1= Neurons in layer 1 Shoot for atleast 100 (default: 1) --depth= Rows of data to predict ahead for matches/learning (default: 1) --selector= Selector (default: Gdax.BTC-USD) --min_periods= Periods to calculate learn from (default: 1000) --min_predict= Periods to predict next number from (default: 1) --momentum= momentum of prediction (default: 0.9) --decay= decay of prediction, use teeny tiny increments (default: 0.1) --threads= Number of processing threads you'd like to run (best for sim) (default: 1) --learns= Number of times to 'learn' the neural network with past data (default: 2) noop description: Just do nothing. Can be used to e.g. for training the strategy. options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) rsi description: Attempts to buy low and sell high by tracking RSI high-water readings. options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --rsi_periods= number of RSI periods --oversold_rsi= buy when RSI reaches or drops below this value (default: 30) --overbought_rsi= sell when RSI reaches or goes above this value (default: 82) --rsi_recover= allow RSI to recover this many points before buying (default: 3) --rsi_drop= allow RSI to fall this many points before selling (default: 0) --rsi_divisor= sell when RSI reaches high-water reading divided by this value (default: 2) sar description: Parabolic SAR options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --sar_af= acceleration factor for parabolic SAR (default: 0.015) --sar_max_af= max acceleration factor for parabolic SAR (default: 0.3) speed description: Trade when % change from last two 1m periods is higher than average. options: --period= period length, same as --period_length (default: 1m) --period_length= period length, same as --period (default: 1m) --min_periods= min. number of history periods (default: 3000) --baseline_periods= lookback periods for volatility baseline (default: 3000) --trigger_factor= multiply with volatility baseline EMA to get trigger value (default: 1.6) srsi_macd description: Stochastic MACD Strategy options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) --min_periods= min. number of history periods (default: 200) --rsi_periods= number of RSI periods --srsi_periods= number of RSI periods (default: 9) --srsi_k= %D line (default: 5) --srsi_d= %D line (default: 3) --oversold_rsi= buy when RSI reaches or drops below this value (default: 20) --overbought_rsi= sell when RSI reaches or goes above this value (default: 80) --ema_short_period= number of periods for the shorter EMA (default: 24) --ema_long_period= number of periods for the longer EMA (default: 200) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) stddev description: Buy when standard deviation and mean increase, sell on mean decrease. options: --period= period length, set poll trades to 100ms, poll order 1000ms. Same as --period_length (default: 100ms) --period_length= period length, set poll trades to 100ms, poll order 1000ms. Same as --period (default: 100ms) --trendtrades_1= Trades for array 1 to be subtracted stddev and mean from (default: 5) --trendtrades_2= Trades for array 2 to be calculated stddev and mean from (default: 53) --min_periods= min_periods (default: 1250) ta_ema description: Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI. options: --period= period length, same as --period_length (default: 10m) --period_length= period length, same as --period (default: 10m) --min_periods= min. number of history periods (default: 52) --trend_ema= number of periods for trend EMA (default: 20) --neutral_rate= avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter) (default: 0.06) --oversold_rsi_periods= number of periods for oversold RSI (default: 20) --oversold_rsi= buy when RSI reaches this value (default: 30) ta_macd description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_macd_ext description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0) with controllable talib TA types options: --period= period length, same as --period_length (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --fast_ma_type= fast_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --slow_ma_type= slow_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --signal_ma_type= signal_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: null) --default_ma_type= set default ma_type for fast, slow and signal. You are able to overwrite single types separately (fast_ma_type, slow_ma_type, signal_ma_type) (default: SMA) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_trix description: TRIX - 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA with rsi oversold options: --period= period length eg 10m (default: 5m) --timeperiod= timeperiod for TRIX (default: 30) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) trend_ema (default) description: Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI. options: --period= period length, same as --period_length (default: 2m) --period_length= period length, same as --period (default: 2m) --min_periods= min. number of history periods (default: 52) --trend_ema= number of periods for trend EMA (default: 26) --neutral_rate= avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter) (default: auto) --oversold_rsi_periods= number of periods for oversold RSI (default: 14) --oversold_rsi= buy when RSI reaches this value (default: 10) ta_ppo description: PPO - Percentage Price Oscillator with rsi oversold options: --period= period length, same as --period_length (default: 10m) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --ma_type== moving average type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 (default: SMA) --overbought_rsi= sold when RSI exceeds this value (default: 70) ta_ultosc description: ULTOSC - Ultimate Oscillator with rsi oversold options: --period= period length eg 5m (default: 5m) --min_periods= min. number of history periods (default: 52) --signal= Provide signal and indicator "simple" (buy@65, sell@50), "low" (buy@65, sell@30), "trend" (buy@30, sell@70) (default: simple) --timeperiod1= talib ULTOSC timeperiod1 (default: 7) --timeperiod2= talib ULTOSC timeperiod2 (default: 14) --timeperiod3= talib ULTOSC timeperiod3 (default: 28) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 90) ti_hma description: HMA - Hull Moving Average options: --period= period length eg 10m (default: 15m) --min_periods= min. number of history periods (default: 52) --trend_hma= number of periods for trend hma (default: 36) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) trendline description: Calculate a trendline and trade when trend is positive vs negative. options: --period= period length (default: 30s) --period_length= period length (default: 30s) --lastpoints= Number of trades for short trend average (default: 100) --avgpoints= Number of trades for long trend average (default: 1000) --lastpoints2= Number of trades for short trend average (default: 10) --avgpoints2= Number of trades for long trend average (default: 100) --min_periods= Basically avgpoints + a BUNCH of more preroll periods for anything less than 5s period (default: 15000) --markup_sell_pct= test (default: 0) --markdown_buy_pct= test (default: 0) trust_distrust description: Sell when price higher than $sell_min% and highest point - $sell_threshold% is reached. Buy when lowest price point + $buy_threshold% reached. options: --period= period length, same as --period_length (default: 30m) --period_length= period length, same as --period (default: 30m) --min_periods= min. number of history periods (default: 52) --sell_threshold= sell when the top drops at least below this percentage (default: 2) --sell_threshold_max= sell when the top drops lower than this max, regardless of sell_min (panic sell, 0 to disable) (default: 0) --sell_min= do not act on anything unless the price is this percentage above the original price (default: 1) --buy_threshold= buy when the bottom increased at least above this percentage (default: 2) --buy_threshold_max= wait for multiple buy signals before buying (kill whipsaw, 0 to disable) (default: 0) --greed= sell if we reach this much profit (0 to be greedy and either win or lose) (default: 0) wavetrend description: Buy when (Signal < Oversold) and sell when (Signal > Overbought). options: --period= period length, same as --period_length (default: 1h) --period_length= period length, same as --period (default: 1h) --min_periods= min. number of history periods (default: 21) --wavetrend_channel_length= wavetrend channel length (default: 10) --wavetrend_average_length= wavetrend average length (default: 21) --wavetrend_overbought_1= wavetrend overbought limit 1 (default: 60) --wavetrend_overbought_2= wavetrend overbought limit 2 (default: 53) --wavetrend_oversold_1= wavetrend oversold limit 1 (default: -60) --wavetrend_oversold_2= wavetrend oversold limit 2 (default: -53) --wavetrend_trends= act on trends instead of limits (default: false) --overbought_rsi_periods= number of periods for overbought RSI (default: 9) --overbought_rsi= sold when RSI exceeds this value (default: 80) ``` ================================================ FILE: docs/strategies/macd.md ================================================ ### The `macd` strategy The moving average convergence divergence calculation is a lagging indicator, used to follow trends. - Can be very effective for trading periods of 1h, with a shorter period like 15m it seems too erratic and the Moving Averages are kind of lost. - It's not firing multiple 'buy' or 'sold' signals, only one per trend, which seems to lead to a better quality trading scheme. - Especially when the bot will enter in the middle of a trend, it avoids buying unless it's the beginning of the trend. ================================================ FILE: docs/strategies/noop.md ================================================ ### The `noop` strategy If you want to use the bot without it trading for you, but just use it for the balance overview and manual trades, you can start the bot with `--strategy noop`, the bot will not trade automatically. ================================================ FILE: docs/strategies/rsi.md ================================================ ### The `rsi` strategy Attempts to buy low and sell high by tracking RSI high-water readings. - Effective in sideways markets or markets that tend to recover after price drops. - Risky to use in bear markets, since the algorithm depends on price recovery. - If the other strategies are losing you money, this strategy may perform better, since it basically "reverses the signals" and anticipates a reversal instead of expecting the trend to continue. ================================================ FILE: docs/strategies/sar.md ================================================ ### The `sar` strategy Uses a [Parabolic SAR](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:parabolic_sar) indicator to trade when SAR trend reverses. - Tends to generate earlier signals than EMA-based strategies, resulting in better capture of highs and lows, and better protection against quick price drops. - Does not perform well in sideways (non-trending) markets, generating more whipsaws than EMA-based strategies. - Most effective with short period (default is 2m), which means it generates 50-100 trades/day, so only usable on GDAX (with 0% maker fee) at the moment. - Tested live, [results here](https://github.com/carlos8f/zenbot/pull/246#issuecomment-307528347) ================================================ FILE: docs/strategies/speed.md ================================================ ### The `speed` strategy Trade when % change from last two 1m periods is higher than average. **This strategy is experimental and has WILDLY varying sim results. NOT RECOMMENDED YET.** - Like the sar strategy, this generates early signals and can be effective in volatile markets and for sudden price drop protection. - Its weakness is that it performs very poorly in low-volatility situations and misses signals from gradually developing trends. ================================================ FILE: docs/strategies/trend_ema.md ================================================ ### The `trend_ema` strategy - The default strategy is called `trend_ema` and resides at `./extensions/strategies/trend_ema`. - Defaults to using a 2m period, but you can override this with adding e.g. `--period=5m` to the `sim` or `trade` commands. - Computes the 26-period EMA of the current price, and calculates the percent change from the last period's EMA to get the `trend_ema_rate` - Considers `trend_ema_rate >= 0` an upwards trend and `trend_ema_rate < 0` a downwards trend - Filters out low values (whipsaws) by `neutral_rate`, which when set to `auto`, uses the standard deviation of the `trend_ema_rate` as a variable noise filter. - Buys at the beginning of upwards trend, sells at the beginning of downwards trend - If `oversold_rsi` is set, tries to buy when the RSI dips below that value, and then starts to recover (a counterpart to `--profit_stop_enable_pct`, which sells when a percent of profit is reached, and then dips) - The bot will always try to avoid trade fees, by using post-only orders and thus being a market "maker" instead of a "taker". Some exchanges will, however, not offer maker discounts. ================================================ FILE: docs/strategies/tweaking.md ================================================ ### Tips for tweaking options - Trade frequency is adjusted with a combination of `--period` and `--trend_ema`. For example, if you want more frequent trading, try `--period=5m` or `--trend_ema=15` or both. If you get too many ping-pong trades or losses from fees, try increasing `period` or `trend_ema` or increasing `neutral_rate`. - Sometimes it's tempting to tell the bot trade very often. Try to resist this urge, and go for quality over quantity, since each trade comes with a decent amount of slippage and whipsaw risk. - `--oversold_rsi=` will try to buy when the price dives. This is one of the ways to get profit above buy/hold, but setting it too high might result in a loss if the price continues to fall. - In a market with predictable price surges and corrections, `--profit_stop_enable_pct=10` will try to sell when the last buy hits 10% profit and then drops to 9% (the drop % is set with `--profit_stop_pct`). However in strong, long uptrends this option may end up causing a sell too early. - For Kraken and GDAX you may wish to use `--order_type="taker"`, this uses market orders instead of limit orders. You usually pay a higher fee, but you can be sure that your order is filled instantly. This means that the sim will more closely match your live trading. Please note that GDAX does not charge maker fees (limit orders), so you will need to choose between not paying fees and running the risk orders do not get filled on time, or paying somewhat high % of fees and making sure your orders are always filled on time. ================================================ FILE: extensions/README.md ================================================ # zenbot extensions To support various exchanges, strategies or notifiers, zenbot "extensions" can be made. You may have to `npm install` in the extension directory, and/or copy and configure `conf-sample.js` to `conf.js` for it to work. ================================================ FILE: extensions/exchanges/_stub/_codemap.js ================================================ module.exports = { _ns: 'zenbot', 'exchanges.stub': require('./exchange'), 'exchanges.list[]': '#exchanges.stub' } ================================================ FILE: extensions/exchanges/_stub/exchange.js ================================================ const superagent = require('superagent') module.exports = function container (conf) { var theExchange = {} // TODO: phase out, in favor of calling the method getDirection(). // It will help define a clean interface/design for future exchange plugins. theExchange.historyScan = conf.historyScan || 'backward' // TODO: phase the use of the name out.. define a cleaner interface for exchanges, so its easier to define how to write one. theExchange.name = 'stub' theExchange.getName = function() { return 'stub' } theExchange.getDirection = function() { return 'backward' } theExchange.getMakerFee = function() { return 0.1 } theExchange.getTakerFee = function() { return 0.1 } theExchange.getProducts = function () { return require('./products.json') } theExchange.getTrades = function (opts, cb) { var url = 'http://localhost:7802/' if (opts.to !== undefined) { url += '?mostRecentTradeId=' + opts.to } superagent.get(url).end(function (err, response) { var v = JSON.parse(response.text) var rtn = [] v.forEach((vv) => { var obj = JSON.parse(vv) obj.id = rtn.push(obj) }) cb(null, rtn) // TODO: handle the case where there is no server on the other end }) } return theExchange } ================================================ FILE: extensions/exchanges/_stub/products.json ================================================ [ { "asset": "BTC", "currency": "USD", "min_size": "0.002", "max_size": "2000.0", "increment": "0.001", "label": "BTC/USD" } ] ================================================ FILE: extensions/exchanges/binance/exchange.js ================================================ const ccxt = require('ccxt') , path = require('path') // eslint-disable-next-line no-unused-vars , colors = require('colors') , _ = require('lodash') module.exports = function binance (conf) { var public_client, authed_client function publicClient () { if (!public_client) public_client = new ccxt.binance({ 'apiKey': '', 'secret': '', 'options': { 'adjustForTimeDifference': true } }) return public_client } function authedClient () { if (!authed_client) { if (!conf.binance || !conf.binance.key || conf.binance.key === 'YOUR-API-KEY') { throw new Error('please configure your Binance credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new ccxt.binance({ 'apiKey': conf.binance.key, 'secret': conf.binance.secret, 'options': { 'adjustForTimeDifference': true }, enableRateLimit: true }) } return authed_client } /** * Convert BNB-BTC to BNB/BTC * * @param product_id BNB-BTC * @returns {string} */ function joinProduct(product_id) { let split = product_id.split('-') return split[0] + '/' + split[1] } function retry (method, args, err) { if (method !== 'getTrades') { console.error(('\nBinance API is down! unable to call ' + method + ', retrying in 20s').red) if (err) console.error(err) console.error(args.slice(0, -1)) } setTimeout(function () { exchange[method].apply(exchange, args) }, 20000) } var orders = {} var exchange = { name: 'binance', historyScan: 'forward', historyScanUsesTime: true, makerFee: 0.1, takerFee: 0.1, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() var startTime = null var args = {} if (opts.from) { startTime = opts.from } else { startTime = parseInt(opts.to, 10) - 3600000 args['endTime'] = opts.to } const symbol = joinProduct(opts.product_id) client.fetchTrades(symbol, startTime, undefined, args).then(result => { if (result.length === 0 && opts.from) { // client.fetchTrades() only returns trades in an 1 hour interval. // So we use fetchOHLCV() to detect trade appart from more than 1h. // Note: it's done only in forward mode. const time_diff = client.options['timeDifference'] if (startTime + time_diff < (new Date()).getTime() - 3600000) { // startTime is older than 1 hour ago. return client.fetchOHLCV(symbol, undefined, startTime) .then(ohlcv => { return ohlcv.length ? client.fetchTrades(symbol, ohlcv[0][0]) : [] }) } } return result }).then(result => { var trades = result.map(trade => ({ trade_id: trade.id, time: trade.timestamp, size: parseFloat(trade.amount), price: parseFloat(trade.price), side: trade.side })) cb(null, trades) }).catch(function (error) { console.error('An error occurred', error) return retry('getTrades', func_args) }) }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.fetchBalance().then(result => { var balance = {asset: 0, currency: 0} Object.keys(result).forEach(function (key) { if (key === opts.currency) { balance.currency = result[key].free + result[key].used balance.currency_hold = result[key].used } if (key === opts.asset) { balance.asset = result[key].free + result[key].used balance.asset_hold = result[key].used } }) cb(null, balance) }) .catch(function (error) { console.error('An error occurred', error) return retry('getBalance', func_args) }) }, getQuote: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchTicker(joinProduct(opts.product_id)).then(result => { cb(null, { bid: result.bid, ask: result.ask }) }) .catch(function (error) { console.error('An error occurred', error) return retry('getQuote', func_args) }) }, getDepth: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchOrderBook(joinProduct(opts.product_id), {limit: opts.limit}).then(result => { cb(null, result) }) .catch(function(error) { console.error('An error ocurred', error) return retry('getDepth', func_args) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.cancelOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { if (body && (body.message === 'Order already done' || body.message === 'order not found')) return cb() cb(null) }, function(err){ // match error against string: // "binance {"code":-2011,"msg":"UNKNOWN_ORDER"}" if (err) { // decide if this error is allowed for a retry if (err.message && err.message.match(new RegExp(/-2011|UNKNOWN_ORDER/))) { console.error(('\ncancelOrder retry - unknown Order: ' + JSON.stringify(opts) + ' - ' + err).cyan) } else { // retry is allowed for this error return retry('cancelOrder', func_args, err) } } cb() }) }, buy: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } opts.type = 'limit' var args = {} if (opts.order_type === 'taker') { delete opts.post_only opts.type = 'market' } else { args.timeInForce = 'GTC' } opts.side = 'buy' delete opts.order_type var order = {} client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { if (result && result.message === 'Insufficient funds') { order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } order = { id: result ? result.id : null, status: 'open', price: opts.price, size: this.roundToNearest(opts.size, opts), post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } orders['~' + result.id] = order cb(null, order) }).catch(function (error) { console.error('An error occurred', error) // decide if this error is allowed for a retry: // {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"} // {"code":-2010,"msg":"Account has insufficient balance for requested action"} if (error.message.match(new RegExp(/-1013|MIN_NOTIONAL|-2010/))) { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } return retry('buy', func_args) }) }, sell: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } opts.type = 'limit' var args = {} if (opts.order_type === 'taker') { delete opts.post_only opts.type = 'market' } else { args.timeInForce = 'GTC' } opts.side = 'sell' delete opts.order_type var order = {} client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { if (result && result.message === 'Insufficient funds') { order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } order = { id: result ? result.id : null, status: 'open', price: opts.price, size: this.roundToNearest(opts.size, opts), post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } orders['~' + result.id] = order cb(null, order) }).catch(function (error) { console.error('An error occurred', error) // decide if this error is allowed for a retry: // {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"} // {"code":-2010,"msg":"Account has insufficient balance for requested action"} if (error.message.match(new RegExp(/-1013|MIN_NOTIONAL|-2010/))) { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } return retry('sell', func_args) }) }, roundToNearest: function(numToRound, opts) { var numToRoundTo = _.find(this.getProducts(), { 'asset': opts.product_id.split('-')[0], 'currency': opts.product_id.split('-')[1] }).min_size numToRoundTo = 1 / (numToRoundTo) return Math.floor(numToRound * numToRoundTo) / numToRoundTo }, getOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() var order = orders['~' + opts.order_id] client.fetchOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { if (body.status !== 'open' && body.status !== 'canceled') { order.status = 'done' order.done_at = new Date().getTime() order.price = parseFloat(body.price) order.filled_size = parseFloat(body.amount) - parseFloat(body.remaining) return cb(null, order) } cb(null, order) }, function(err) { return retry('getOrder', func_args, err) }) }, getCursor: function (trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/binance/products.json ================================================ [ { "id": "ETHBTC", "asset": "ETH", "currency": "BTC", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "ETH/BTC" }, { "id": "LTCBTC", "asset": "LTC", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LTC/BTC" }, { "id": "BNBBTC", "asset": "BNB", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "BNB/BTC" }, { "id": "NEOBTC", "asset": "NEO", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "NEO/BTC" }, { "id": "QTUMETH", "asset": "QTUM", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "QTUM/ETH" }, { "id": "EOSETH", "asset": "EOS", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "EOS/ETH" }, { "id": "SNTETH", "asset": "SNT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SNT/ETH" }, { "id": "BNTETH", "asset": "BNT", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "BNT/ETH" }, { "id": "BCCBTC", "asset": "BCC", "currency": "BTC", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BCC/BTC" }, { "id": "GASBTC", "asset": "GAS", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "GAS/BTC" }, { "id": "BNBETH", "asset": "BNB", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "BNB/ETH" }, { "id": "BTCUSDT", "asset": "BTC", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/USDT" }, { "id": "ETHUSDT", "asset": "ETH", "currency": "USDT", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/USDT" }, { "id": "HSRBTC", "asset": "HSR", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "HSR/BTC" }, { "id": "OAXETH", "asset": "OAX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "OAX/ETH" }, { "id": "DNTETH", "asset": "DNT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DNT/ETH" }, { "id": "MCOETH", "asset": "MCO", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "MCO/ETH" }, { "id": "ICNETH", "asset": "ICN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ICN/ETH" }, { "id": "MCOBTC", "asset": "MCO", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "MCO/BTC" }, { "id": "WTCBTC", "asset": "WTC", "currency": "BTC", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "WTC/BTC" }, { "id": "WTCETH", "asset": "WTC", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "WTC/ETH" }, { "id": "LRCBTC", "asset": "LRC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LRC/BTC" }, { "id": "LRCETH", "asset": "LRC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LRC/ETH" }, { "id": "QTUMBTC", "asset": "QTUM", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "QTUM/BTC" }, { "id": "YOYOBTC", "asset": "YOYOW", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "YOYOW/BTC" }, { "id": "OMGBTC", "asset": "OMG", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "OMG/BTC" }, { "id": "OMGETH", "asset": "OMG", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "OMG/ETH" }, { "id": "ZRXBTC", "asset": "ZRX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ZRX/BTC" }, { "id": "ZRXETH", "asset": "ZRX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ZRX/ETH" }, { "id": "STRATBTC", "asset": "STRAT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STRAT/BTC" }, { "id": "STRATETH", "asset": "STRAT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "STRAT/ETH" }, { "id": "SNGLSBTC", "asset": "SNGLS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SNGLS/BTC" }, { "id": "SNGLSETH", "asset": "SNGLS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SNGLS/ETH" }, { "id": "BQXBTC", "asset": "BQX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BQX/BTC" }, { "id": "BQXETH", "asset": "BQX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BQX/ETH" }, { "id": "KNCBTC", "asset": "KNC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "KNC/BTC" }, { "id": "KNCETH", "asset": "KNC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "KNC/ETH" }, { "id": "FUNBTC", "asset": "FUN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FUN/BTC" }, { "id": "FUNETH", "asset": "FUN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FUN/ETH" }, { "id": "SNMBTC", "asset": "SNM", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "SNM/BTC" }, { "id": "SNMETH", "asset": "SNM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SNM/ETH" }, { "id": "NEOETH", "asset": "NEO", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "NEO/ETH" }, { "id": "IOTABTC", "asset": "IOTA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOTA/BTC" }, { "id": "IOTAETH", "asset": "IOTA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOTA/ETH" }, { "id": "LINKBTC", "asset": "LINK", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "LINK/BTC" }, { "id": "LINKETH", "asset": "LINK", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LINK/ETH" }, { "id": "XVGBTC", "asset": "XVG", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XVG/BTC" }, { "id": "XVGETH", "asset": "XVG", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XVG/ETH" }, { "id": "SALTBTC", "asset": "SALT", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "SALT/BTC" }, { "id": "SALTETH", "asset": "SALT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "SALT/ETH" }, { "id": "MDABTC", "asset": "MDA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MDA/BTC" }, { "id": "MDAETH", "asset": "MDA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "MDA/ETH" }, { "id": "MTLBTC", "asset": "MTL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MTL/BTC" }, { "id": "MTLETH", "asset": "MTL", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "MTL/ETH" }, { "id": "SUBBTC", "asset": "SUB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SUB/BTC" }, { "id": "SUBETH", "asset": "SUB", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SUB/ETH" }, { "id": "EOSBTC", "asset": "EOS", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "EOS/BTC" }, { "id": "SNTBTC", "asset": "SNT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SNT/BTC" }, { "id": "ETCETH", "asset": "ETC", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ETC/ETH" }, { "id": "ETCBTC", "asset": "ETC", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ETC/BTC" }, { "id": "MTHBTC", "asset": "MTH", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MTH/BTC" }, { "id": "MTHETH", "asset": "MTH", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MTH/ETH" }, { "id": "ENGBTC", "asset": "ENG", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ENG/BTC" }, { "id": "ENGETH", "asset": "ENG", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ENG/ETH" }, { "id": "DNTBTC", "asset": "DNT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DNT/BTC" }, { "id": "ZECBTC", "asset": "ZEC", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "ZEC/BTC" }, { "id": "ZECETH", "asset": "ZEC", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "ZEC/ETH" }, { "id": "BNTBTC", "asset": "BNT", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "BNT/BTC" }, { "id": "ASTBTC", "asset": "AST", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AST/BTC" }, { "id": "ASTETH", "asset": "AST", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "AST/ETH" }, { "id": "DASHBTC", "asset": "DASH", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "DASH/BTC" }, { "id": "DASHETH", "asset": "DASH", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "DASH/ETH" }, { "id": "OAXBTC", "asset": "OAX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OAX/BTC" }, { "id": "ICNBTC", "asset": "ICN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ICN/BTC" }, { "id": "BTGBTC", "asset": "BTG", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "BTG/BTC" }, { "id": "BTGETH", "asset": "BTG", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "BTG/ETH" }, { "id": "EVXBTC", "asset": "EVX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "EVX/BTC" }, { "id": "EVXETH", "asset": "EVX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "EVX/ETH" }, { "id": "REQBTC", "asset": "REQ", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "REQ/BTC" }, { "id": "REQETH", "asset": "REQ", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "REQ/ETH" }, { "id": "VIBBTC", "asset": "VIB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VIB/BTC" }, { "id": "VIBETH", "asset": "VIB", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VIB/ETH" }, { "id": "HSRETH", "asset": "HSR", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "HSR/ETH" }, { "id": "TRXBTC", "asset": "TRX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TRX/BTC" }, { "id": "TRXETH", "asset": "TRX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TRX/ETH" }, { "id": "POWRBTC", "asset": "POWR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POWR/BTC" }, { "id": "POWRETH", "asset": "POWR", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POWR/ETH" }, { "id": "ARKBTC", "asset": "ARK", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARK/BTC" }, { "id": "ARKETH", "asset": "ARK", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ARK/ETH" }, { "id": "YOYOETH", "asset": "YOYOW", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "YOYOW/ETH" }, { "id": "XRPBTC", "asset": "XRP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XRP/BTC" }, { "id": "XRPETH", "asset": "XRP", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XRP/ETH" }, { "id": "MODBTC", "asset": "MOD", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "MOD/BTC" }, { "id": "MODETH", "asset": "MOD", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "MOD/ETH" }, { "id": "ENJBTC", "asset": "ENJ", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ENJ/BTC" }, { "id": "ENJETH", "asset": "ENJ", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ENJ/ETH" }, { "id": "STORJBTC", "asset": "STORJ", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STORJ/BTC" }, { "id": "STORJETH", "asset": "STORJ", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "STORJ/ETH" }, { "id": "BNBUSDT", "asset": "BNB", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/USDT" }, { "id": "VENBNB", "asset": "VEN", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "VEN/BNB" }, { "id": "YOYOBNB", "asset": "YOYOW", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "YOYOW/BNB" }, { "id": "POWRBNB", "asset": "POWR", "currency": "BNB", "min_size": "1.00000000", "max_size": "900000.00000000", "min_total": "0.10000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "POWR/BNB" }, { "id": "VENBTC", "asset": "VEN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VEN/BTC" }, { "id": "VENETH", "asset": "VEN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VEN/ETH" }, { "id": "KMDBTC", "asset": "KMD", "currency": "BTC", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "KMD/BTC" }, { "id": "KMDETH", "asset": "KMD", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "KMD/ETH" }, { "id": "NULSBNB", "asset": "NULS", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NULS/BNB" }, { "id": "RCNBTC", "asset": "RCN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RCN/BTC" }, { "id": "RCNETH", "asset": "RCN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RCN/ETH" }, { "id": "RCNBNB", "asset": "RCN", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "RCN/BNB" }, { "id": "NULSBTC", "asset": "NULS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NULS/BTC" }, { "id": "NULSETH", "asset": "NULS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NULS/ETH" }, { "id": "RDNBTC", "asset": "RDN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RDN/BTC" }, { "id": "RDNETH", "asset": "RDN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "RDN/ETH" }, { "id": "RDNBNB", "asset": "RDN", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RDN/BNB" }, { "id": "XMRBTC", "asset": "XMR", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "XMR/BTC" }, { "id": "XMRETH", "asset": "XMR", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "XMR/ETH" }, { "id": "DLTBNB", "asset": "DLT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "DLT/BNB" }, { "id": "WTCBNB", "asset": "WTC", "currency": "BNB", "min_size": "0.10000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "WTC/BNB" }, { "id": "DLTBTC", "asset": "DLT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DLT/BTC" }, { "id": "DLTETH", "asset": "DLT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DLT/ETH" }, { "id": "AMBBTC", "asset": "AMB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AMB/BTC" }, { "id": "AMBETH", "asset": "AMB", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AMB/ETH" }, { "id": "AMBBNB", "asset": "AMB", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "AMB/BNB" }, { "id": "BCCETH", "asset": "BCC", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "BCC/ETH" }, { "id": "BCCUSDT", "asset": "BCC", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCC/USDT" }, { "id": "BCCBNB", "asset": "BCC", "currency": "BNB", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "0.10000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCC/BNB" }, { "id": "BATBTC", "asset": "BAT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BAT/BTC" }, { "id": "BATETH", "asset": "BAT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BAT/ETH" }, { "id": "BATBNB", "asset": "BAT", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "BAT/BNB" }, { "id": "BCPTBTC", "asset": "BCPT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BCPT/BTC" }, { "id": "BCPTETH", "asset": "BCPT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BCPT/ETH" }, { "id": "BCPTBNB", "asset": "BCPT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BCPT/BNB" }, { "id": "ARNBTC", "asset": "ARN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARN/BTC" }, { "id": "ARNETH", "asset": "ARN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARN/ETH" }, { "id": "GVTBTC", "asset": "GVT", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "GVT/BTC" }, { "id": "GVTETH", "asset": "GVT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "GVT/ETH" }, { "id": "CDTBTC", "asset": "CDT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CDT/BTC" }, { "id": "CDTETH", "asset": "CDT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CDT/ETH" }, { "id": "GXSBTC", "asset": "GXS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GXS/BTC" }, { "id": "GXSETH", "asset": "GXS", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "GXS/ETH" }, { "id": "NEOUSDT", "asset": "NEO", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/USDT" }, { "id": "NEOBNB", "asset": "NEO", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NEO/BNB" }, { "id": "POEBTC", "asset": "POE", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POE/BTC" }, { "id": "POEETH", "asset": "POE", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POE/ETH" }, { "id": "QSPBTC", "asset": "QSP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QSP/BTC" }, { "id": "QSPETH", "asset": "QSP", "currency": "ETH", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QSP/ETH" }, { "id": "QSPBNB", "asset": "QSP", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "QSP/BNB" }, { "id": "BTSBTC", "asset": "BTS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BTS/BTC" }, { "id": "BTSETH", "asset": "BTS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BTS/ETH" }, { "id": "BTSBNB", "asset": "BTS", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BTS/BNB" }, { "id": "XZCBTC", "asset": "XZC", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "XZC/BTC" }, { "id": "XZCETH", "asset": "XZC", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "XZC/ETH" }, { "id": "XZCBNB", "asset": "XZC", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XZC/BNB" }, { "id": "LSKBTC", "asset": "LSK", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "LSK/BTC" }, { "id": "LSKETH", "asset": "LSK", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LSK/ETH" }, { "id": "LSKBNB", "asset": "LSK", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LSK/BNB" }, { "id": "TNTBTC", "asset": "TNT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TNT/BTC" }, { "id": "TNTETH", "asset": "TNT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TNT/ETH" }, { "id": "FUELBTC", "asset": "FUEL", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FUEL/BTC" }, { "id": "FUELETH", "asset": "FUEL", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FUEL/ETH" }, { "id": "MANABTC", "asset": "MANA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MANA/BTC" }, { "id": "MANAETH", "asset": "MANA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MANA/ETH" }, { "id": "BCDBTC", "asset": "BCD", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BCD/BTC" }, { "id": "BCDETH", "asset": "BCD", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "BCD/ETH" }, { "id": "DGDBTC", "asset": "DGD", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "DGD/BTC" }, { "id": "DGDETH", "asset": "DGD", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "DGD/ETH" }, { "id": "IOTABNB", "asset": "IOTA", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "IOTA/BNB" }, { "id": "ADXBTC", "asset": "ADX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ADX/BTC" }, { "id": "ADXETH", "asset": "ADX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ADX/ETH" }, { "id": "ADXBNB", "asset": "ADX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ADX/BNB" }, { "id": "ADABTC", "asset": "ADA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ADA/BTC" }, { "id": "ADAETH", "asset": "ADA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ADA/ETH" }, { "id": "PPTBTC", "asset": "PPT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PPT/BTC" }, { "id": "PPTETH", "asset": "PPT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "PPT/ETH" }, { "id": "CMTBTC", "asset": "CMT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CMT/BTC" }, { "id": "CMTETH", "asset": "CMT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CMT/ETH" }, { "id": "CMTBNB", "asset": "CMT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CMT/BNB" }, { "id": "XLMBTC", "asset": "XLM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XLM/BTC" }, { "id": "XLMETH", "asset": "XLM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XLM/ETH" }, { "id": "XLMBNB", "asset": "XLM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "XLM/BNB" }, { "id": "CNDBTC", "asset": "CND", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CND/BTC" }, { "id": "CNDETH", "asset": "CND", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CND/ETH" }, { "id": "CNDBNB", "asset": "CND", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "CND/BNB" }, { "id": "LENDBTC", "asset": "LEND", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LEND/BTC" }, { "id": "LENDETH", "asset": "LEND", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LEND/ETH" }, { "id": "WABIBTC", "asset": "WABI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WABI/BTC" }, { "id": "WABIETH", "asset": "WABI", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WABI/ETH" }, { "id": "WABIBNB", "asset": "WABI", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "WABI/BNB" }, { "id": "LTCETH", "asset": "LTC", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "LTC/ETH" }, { "id": "LTCUSDT", "asset": "LTC", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/USDT" }, { "id": "LTCBNB", "asset": "LTC", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.00100000", "label": "LTC/BNB" }, { "id": "TNBBTC", "asset": "TNB", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TNB/BTC" }, { "id": "TNBETH", "asset": "TNB", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TNB/ETH" }, { "id": "WAVESBTC", "asset": "WAVES", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "WAVES/BTC" }, { "id": "WAVESETH", "asset": "WAVES", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "WAVES/ETH" }, { "id": "WAVESBNB", "asset": "WAVES", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "WAVES/BNB" }, { "id": "GTOBTC", "asset": "GTO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GTO/BTC" }, { "id": "GTOETH", "asset": "GTO", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GTO/ETH" }, { "id": "GTOBNB", "asset": "GTO", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "GTO/BNB" }, { "id": "ICXBTC", "asset": "ICX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ICX/BTC" }, { "id": "ICXETH", "asset": "ICX", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ICX/ETH" }, { "id": "ICXBNB", "asset": "ICX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "ICX/BNB" }, { "id": "OSTBTC", "asset": "OST", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OST/BTC" }, { "id": "OSTETH", "asset": "OST", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OST/ETH" }, { "id": "OSTBNB", "asset": "OST", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "OST/BNB" }, { "id": "ELFBTC", "asset": "ELF", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ELF/BTC" }, { "id": "ELFETH", "asset": "ELF", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ELF/ETH" }, { "id": "AIONBTC", "asset": "AION", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AION/BTC" }, { "id": "AIONETH", "asset": "AION", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "AION/ETH" }, { "id": "AIONBNB", "asset": "AION", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "AION/BNB" }, { "id": "NEBLBTC", "asset": "NEBL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NEBL/BTC" }, { "id": "NEBLETH", "asset": "NEBL", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "NEBL/ETH" }, { "id": "NEBLBNB", "asset": "NEBL", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NEBL/BNB" }, { "id": "BRDBTC", "asset": "BRD", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BRD/BTC" }, { "id": "BRDETH", "asset": "BRD", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BRD/ETH" }, { "id": "BRDBNB", "asset": "BRD", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BRD/BNB" }, { "id": "MCOBNB", "asset": "MCO", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MCO/BNB" }, { "id": "EDOBTC", "asset": "EDO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "EDO/BTC" }, { "id": "EDOETH", "asset": "EDO", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "EDO/ETH" }, { "id": "WINGSBTC", "asset": "WINGS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WINGS/BTC" }, { "id": "WINGSETH", "asset": "WINGS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "WINGS/ETH" }, { "id": "NAVBTC", "asset": "NAV", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NAV/BTC" }, { "id": "NAVETH", "asset": "NAV", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "NAV/ETH" }, { "id": "NAVBNB", "asset": "NAV", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "NAV/BNB" }, { "id": "LUNBTC", "asset": "LUN", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "LUN/BTC" }, { "id": "LUNETH", "asset": "LUN", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LUN/ETH" }, { "id": "TRIGBTC", "asset": "TRIG", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "TRIG/BTC" }, { "id": "TRIGETH", "asset": "TRIG", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "TRIG/ETH" }, { "id": "TRIGBNB", "asset": "TRIG", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRIG/BNB" }, { "id": "APPCBTC", "asset": "APPC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "APPC/BTC" }, { "id": "APPCETH", "asset": "APPC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "APPC/ETH" }, { "id": "APPCBNB", "asset": "APPC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "APPC/BNB" }, { "id": "VIBEBTC", "asset": "VIBE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VIBE/BTC" }, { "id": "VIBEETH", "asset": "VIBE", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "VIBE/ETH" }, { "id": "RLCBTC", "asset": "RLC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RLC/BTC" }, { "id": "RLCETH", "asset": "RLC", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "RLC/ETH" }, { "id": "RLCBNB", "asset": "RLC", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RLC/BNB" }, { "id": "INSBTC", "asset": "INS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "INS/BTC" }, { "id": "INSETH", "asset": "INS", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "INS/ETH" }, { "id": "PIVXBTC", "asset": "PIVX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PIVX/BTC" }, { "id": "PIVXETH", "asset": "PIVX", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "PIVX/ETH" }, { "id": "PIVXBNB", "asset": "PIVX", "currency": "BNB", "min_size": "0.10000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "PIVX/BNB" }, { "id": "IOSTBTC", "asset": "IOST", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOST/BTC" }, { "id": "IOSTETH", "asset": "IOST", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOST/ETH" }, { "id": "CHATBTC", "asset": "CHAT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CHAT/BTC" }, { "id": "CHATETH", "asset": "CHAT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CHAT/ETH" }, { "id": "STEEMBTC", "asset": "STEEM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STEEM/BTC" }, { "id": "STEEMETH", "asset": "STEEM", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "STEEM/ETH" }, { "id": "STEEMBNB", "asset": "STEEM", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "STEEM/BNB" }, { "id": "NANOBTC", "asset": "NANO", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "NANO/BTC" }, { "id": "NANOETH", "asset": "NANO", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "NANO/ETH" }, { "id": "NANOBNB", "asset": "NANO", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NANO/BNB" }, { "id": "VIABTC", "asset": "VIA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VIA/BTC" }, { "id": "VIAETH", "asset": "VIA", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "VIA/ETH" }, { "id": "VIABNB", "asset": "VIA", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "VIA/BNB" }, { "id": "BLZBTC", "asset": "BLZ", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BLZ/BTC" }, { "id": "BLZETH", "asset": "BLZ", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BLZ/ETH" }, { "id": "BLZBNB", "asset": "BLZ", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BLZ/BNB" }, { "id": "AEBTC", "asset": "AE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AE/BTC" }, { "id": "AEETH", "asset": "AE", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "AE/ETH" }, { "id": "AEBNB", "asset": "AE", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AE/BNB" }, { "id": "RPXBTC", "asset": "RPX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RPX/BTC" }, { "id": "RPXETH", "asset": "RPX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RPX/ETH" }, { "id": "RPXBNB", "asset": "RPX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "RPX/BNB" }, { "id": "NCASHBTC", "asset": "NCASH", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NCASH/BTC" }, { "id": "NCASHETH", "asset": "NCASH", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NCASH/ETH" }, { "id": "NCASHBNB", "asset": "NCASH", "currency": "BNB", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "NCASH/BNB" }, { "id": "POABTC", "asset": "POA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POA/BTC" }, { "id": "POAETH", "asset": "POA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POA/ETH" }, { "id": "POABNB", "asset": "POA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "POA/BNB" }, { "id": "ZILBTC", "asset": "ZIL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ZIL/BTC" }, { "id": "ZILETH", "asset": "ZIL", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ZIL/ETH" }, { "id": "ZILBNB", "asset": "ZIL", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ZIL/BNB" }, { "id": "ONTBTC", "asset": "ONT", "currency": "BTC", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "ONT/BTC" }, { "id": "ONTETH", "asset": "ONT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ONT/ETH" }, { "id": "ONTBNB", "asset": "ONT", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "ONT/BNB" }, { "id": "STORMBTC", "asset": "STORM", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STORM/BTC" }, { "id": "STORMETH", "asset": "STORM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STORM/ETH" }, { "id": "STORMBNB", "asset": "STORM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "STORM/BNB" }, { "id": "QTUMBNB", "asset": "QTUM", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "QTUM/BNB" }, { "id": "QTUMUSDT", "asset": "QTUM", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "QTUM/USDT" }, { "id": "XEMBTC", "asset": "XEM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XEM/BTC" }, { "id": "XEMETH", "asset": "XEM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XEM/ETH" }, { "id": "XEMBNB", "asset": "XEM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "XEM/BNB" }, { "id": "WANBTC", "asset": "WAN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WAN/BTC" }, { "id": "WANETH", "asset": "WAN", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "WAN/ETH" }, { "id": "WANBNB", "asset": "WAN", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "WAN/BNB" }, { "id": "WPRBTC", "asset": "WPR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WPR/BTC" }, { "id": "WPRETH", "asset": "WPR", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WPR/ETH" }, { "id": "QLCBTC", "asset": "QLC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QLC/BTC" }, { "id": "QLCETH", "asset": "QLC", "currency": "ETH", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QLC/ETH" }, { "id": "SYSBTC", "asset": "SYS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SYS/BTC" }, { "id": "SYSETH", "asset": "SYS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SYS/ETH" }, { "id": "SYSBNB", "asset": "SYS", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "SYS/BNB" }, { "id": "QLCBNB", "asset": "QLC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "QLC/BNB" }, { "id": "GRSBTC", "asset": "GRS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GRS/BTC" }, { "id": "GRSETH", "asset": "GRS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GRS/ETH" }, { "id": "ADAUSDT", "asset": "ADA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/USDT" }, { "id": "ADABNB", "asset": "ADA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ADA/BNB" }, { "id": "CLOAKBTC", "asset": "CLOAK", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "CLOAK/BTC" }, { "id": "CLOAKETH", "asset": "CLOAK", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "CLOAK/ETH" }, { "id": "GNTBTC", "asset": "GNT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GNT/BTC" }, { "id": "GNTETH", "asset": "GNT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GNT/ETH" }, { "id": "GNTBNB", "asset": "GNT", "currency": "BNB", "min_size": "1.00000000", "max_size": "900000.00000000", "min_total": "0.10000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "GNT/BNB" }, { "id": "LOOMBTC", "asset": "LOOM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LOOM/BTC" }, { "id": "LOOMETH", "asset": "LOOM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LOOM/ETH" }, { "id": "LOOMBNB", "asset": "LOOM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "LOOM/BNB" }, { "id": "XRPUSDT", "asset": "XRP", "currency": "USDT", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/USDT" }, { "id": "BCNBTC", "asset": "BCN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BCN/BTC" }, { "id": "BCNETH", "asset": "BCN", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BCN/ETH" }, { "id": "BCNBNB", "asset": "BCN", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BCN/BNB" }, { "id": "REPBTC", "asset": "REP", "currency": "BTC", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.00100000", "label": "REP/BTC" }, { "id": "REPETH", "asset": "REP", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "REP/ETH" }, { "id": "REPBNB", "asset": "REP", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "REP/BNB" }, { "id": "BTCTUSD", "asset": "BTC", "currency": "TUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/TUSD" }, { "id": "TUSDBTC", "asset": "TUSD", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TUSD/BTC" }, { "id": "ETHTUSD", "asset": "ETH", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/TUSD" }, { "id": "TUSDETH", "asset": "TUSD", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TUSD/ETH" }, { "id": "TUSDBNB", "asset": "TUSD", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TUSD/BNB" }, { "id": "ZENBTC", "asset": "ZEN", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ZEN/BTC" }, { "id": "ZENETH", "asset": "ZEN", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "ZEN/ETH" }, { "id": "ZENBNB", "asset": "ZEN", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ZEN/BNB" }, { "id": "SKYBTC", "asset": "SKY", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SKY/BTC" }, { "id": "SKYETH", "asset": "SKY", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "SKY/ETH" }, { "id": "SKYBNB", "asset": "SKY", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SKY/BNB" }, { "id": "EOSUSDT", "asset": "EOS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/USDT" }, { "id": "EOSBNB", "asset": "EOS", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "EOS/BNB" }, { "id": "CVCBTC", "asset": "CVC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CVC/BTC" }, { "id": "CVCETH", "asset": "CVC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CVC/ETH" }, { "id": "CVCBNB", "asset": "CVC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CVC/BNB" }, { "id": "THETABTC", "asset": "THETA", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "THETA/BTC" }, { "id": "THETAETH", "asset": "THETA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "THETA/ETH" }, { "id": "THETABNB", "asset": "THETA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "THETA/BNB" }, { "id": "XRPBNB", "asset": "XRP", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "XRP/BNB" }, { "id": "TUSDUSDT", "asset": "TUSD", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TUSD/USDT" }, { "id": "IOTAUSDT", "asset": "IOTA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "IOTA/USDT" }, { "id": "XLMUSDT", "asset": "XLM", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/USDT" }, { "id": "IOTXBTC", "asset": "IOTX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOTX/BTC" }, { "id": "IOTXETH", "asset": "IOTX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IOTX/ETH" }, { "id": "QKCBTC", "asset": "QKC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QKC/BTC" }, { "id": "QKCETH", "asset": "QKC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "QKC/ETH" }, { "id": "AGIBTC", "asset": "AGI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AGI/BTC" }, { "id": "AGIETH", "asset": "AGI", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AGI/ETH" }, { "id": "AGIBNB", "asset": "AGI", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "AGI/BNB" }, { "id": "NXSBTC", "asset": "NXS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NXS/BTC" }, { "id": "NXSETH", "asset": "NXS", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "NXS/ETH" }, { "id": "NXSBNB", "asset": "NXS", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NXS/BNB" }, { "id": "ENJBNB", "asset": "ENJ", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ENJ/BNB" }, { "id": "DATABTC", "asset": "DATA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DATA/BTC" }, { "id": "DATAETH", "asset": "DATA", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DATA/ETH" }, { "id": "ONTUSDT", "asset": "ONT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONT/USDT" }, { "id": "TRXBNB", "asset": "TRX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "TRX/BNB" }, { "id": "TRXUSDT", "asset": "TRX", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/USDT" }, { "id": "ETCUSDT", "asset": "ETC", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/USDT" }, { "id": "ETCBNB", "asset": "ETC", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "ETC/BNB" }, { "id": "ICXUSDT", "asset": "ICX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ICX/USDT" }, { "id": "SCBTC", "asset": "SC", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SC/BTC" }, { "id": "SCETH", "asset": "SC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SC/ETH" }, { "id": "SCBNB", "asset": "SC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "SC/BNB" }, { "id": "NPXSBTC", "asset": "NPXS", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NPXS/BTC" }, { "id": "NPXSETH", "asset": "NPXS", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NPXS/ETH" }, { "id": "VENUSDT", "asset": "VEN", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "VEN/USDT" }, { "id": "KEYBTC", "asset": "KEY", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "KEY/BTC" }, { "id": "KEYETH", "asset": "KEY", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "KEY/ETH" }, { "id": "NASBTC", "asset": "NAS", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "NAS/BTC" }, { "id": "NASETH", "asset": "NAS", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "NAS/ETH" }, { "id": "NASBNB", "asset": "NAS", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NAS/BNB" }, { "id": "MFTBTC", "asset": "MFT", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MFT/BTC" }, { "id": "MFTETH", "asset": "MFT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MFT/ETH" }, { "id": "MFTBNB", "asset": "MFT", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MFT/BNB" }, { "id": "DENTBTC", "asset": "DENT", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DENT/BTC" }, { "id": "DENTETH", "asset": "DENT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DENT/ETH" }, { "id": "ARDRBTC", "asset": "ARDR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARDR/BTC" }, { "id": "ARDRETH", "asset": "ARDR", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARDR/ETH" }, { "id": "ARDRBNB", "asset": "ARDR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ARDR/BNB" }, { "id": "NULSUSDT", "asset": "NULS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NULS/USDT" }, { "id": "HOTBTC", "asset": "HOT", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "HOT/BTC" }, { "id": "HOTETH", "asset": "HOT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "HOT/ETH" }, { "id": "VETBTC", "asset": "VET", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VET/BTC" }, { "id": "VETETH", "asset": "VET", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VET/ETH" }, { "id": "VETUSDT", "asset": "VET", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "VET/USDT" }, { "id": "VETBNB", "asset": "VET", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "VET/BNB" }, { "id": "DOCKBTC", "asset": "DOCK", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DOCK/BTC" }, { "id": "DOCKETH", "asset": "DOCK", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DOCK/ETH" }, { "id": "POLYBTC", "asset": "POLY", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POLY/BTC" }, { "id": "POLYBNB", "asset": "POLY", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "POLY/BNB" }, { "id": "PHXBTC", "asset": "PHX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PHX/BTC" }, { "id": "PHXETH", "asset": "PHX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PHX/ETH" }, { "id": "PHXBNB", "asset": "PHX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "PHX/BNB" }, { "id": "HCBTC", "asset": "HC", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "HC/BTC" }, { "id": "HCETH", "asset": "HC", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "HC/ETH" }, { "id": "GOBTC", "asset": "GO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GO/BTC" }, { "id": "GOBNB", "asset": "GO", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "GO/BNB" }, { "id": "PAXBTC", "asset": "PAX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PAX/BTC" }, { "id": "PAXBNB", "asset": "PAX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PAX/BNB" }, { "id": "PAXUSDT", "asset": "PAX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "PAX/USDT" }, { "id": "PAXETH", "asset": "PAX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PAX/ETH" }, { "id": "RVNBTC", "asset": "RVN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RVN/BTC" }, { "id": "RVNBNB", "asset": "RVN", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "RVN/BNB" }, { "id": "DCRBTC", "asset": "DCR", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "DCR/BTC" }, { "id": "DCRBNB", "asset": "DCR", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DCR/BNB" }, { "id": "USDCBNB", "asset": "USDC", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "USDC/BNB" }, { "id": "MITHBTC", "asset": "MITH", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MITH/BTC" }, { "id": "MITHBNB", "asset": "MITH", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "MITH/BNB" }, { "id": "BCHABCBTC", "asset": "BCH", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BCH/BTC" }, { "id": "BCHSVBTC", "asset": "BSV", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BSV/BTC" }, { "id": "BCHABCUSDT", "asset": "BCH", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/USDT" }, { "id": "BCHSVUSDT", "asset": "BSV", "currency": "USDT", "min_size": "0.00001000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BSV/USDT" }, { "id": "BNBPAX", "asset": "BNB", "currency": "PAX", "min_size": "0.00010000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/PAX" }, { "id": "BTCPAX", "asset": "BTC", "currency": "PAX", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/PAX" }, { "id": "ETHPAX", "asset": "ETH", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/PAX" }, { "id": "XRPPAX", "asset": "XRP", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/PAX" }, { "id": "EOSPAX", "asset": "EOS", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/PAX" }, { "id": "XLMPAX", "asset": "XLM", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/PAX" }, { "id": "RENBTC", "asset": "REN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "REN/BTC" }, { "id": "RENBNB", "asset": "REN", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "REN/BNB" }, { "id": "BNBTUSD", "asset": "BNB", "currency": "TUSD", "min_size": "0.00010000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/TUSD" }, { "id": "XRPTUSD", "asset": "XRP", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/TUSD" }, { "id": "EOSTUSD", "asset": "EOS", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/TUSD" }, { "id": "XLMTUSD", "asset": "XLM", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/TUSD" }, { "id": "BNBUSDC", "asset": "BNB", "currency": "USDC", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/USDC" }, { "id": "BTCUSDC", "asset": "BTC", "currency": "USDC", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/USDC" }, { "id": "ETHUSDC", "asset": "ETH", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/USDC" }, { "id": "XRPUSDC", "asset": "XRP", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/USDC" }, { "id": "EOSUSDC", "asset": "EOS", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/USDC" }, { "id": "XLMUSDC", "asset": "XLM", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/USDC" }, { "id": "USDCUSDT", "asset": "USDC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDC/USDT" }, { "id": "ADATUSD", "asset": "ADA", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/TUSD" }, { "id": "TRXTUSD", "asset": "TRX", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/TUSD" }, { "id": "NEOTUSD", "asset": "NEO", "currency": "TUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/TUSD" }, { "id": "TRXXRP", "asset": "TRX", "currency": "XRP", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/XRP" }, { "id": "XZCXRP", "asset": "XZC", "currency": "XRP", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "XZC/XRP" }, { "id": "PAXTUSD", "asset": "PAX", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "PAX/TUSD" }, { "id": "USDCTUSD", "asset": "USDC", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDC/TUSD" }, { "id": "USDCPAX", "asset": "USDC", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDC/PAX" }, { "id": "LINKUSDT", "asset": "LINK", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/USDT" }, { "id": "LINKTUSD", "asset": "LINK", "currency": "TUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/TUSD" }, { "id": "LINKPAX", "asset": "LINK", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LINK/PAX" }, { "id": "LINKUSDC", "asset": "LINK", "currency": "USDC", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/USDC" }, { "id": "WAVESUSDT", "asset": "WAVES", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WAVES/USDT" }, { "id": "WAVESTUSD", "asset": "WAVES", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WAVES/TUSD" }, { "id": "WAVESPAX", "asset": "WAVES", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WAVES/PAX" }, { "id": "WAVESUSDC", "asset": "WAVES", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WAVES/USDC" }, { "id": "BCHABCTUSD", "asset": "BCH", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/TUSD" }, { "id": "BCHABCPAX", "asset": "BCH", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/PAX" }, { "id": "BCHABCUSDC", "asset": "BCH", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/USDC" }, { "id": "BCHSVTUSD", "asset": "BSV", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BSV/TUSD" }, { "id": "BCHSVPAX", "asset": "BSV", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BSV/PAX" }, { "id": "BCHSVUSDC", "asset": "BSV", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BSV/USDC" }, { "id": "LTCTUSD", "asset": "LTC", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/TUSD" }, { "id": "LTCPAX", "asset": "LTC", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/PAX" }, { "id": "LTCUSDC", "asset": "LTC", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/USDC" }, { "id": "TRXPAX", "asset": "TRX", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/PAX" }, { "id": "TRXUSDC", "asset": "TRX", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/USDC" }, { "id": "BTTBTC", "asset": "BTT", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BTT/BTC" }, { "id": "BTTBNB", "asset": "BTT", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BTT/BNB" }, { "id": "BTTUSDT", "asset": "BTT", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BTT/USDT" }, { "id": "BNBUSDS", "asset": "BNB", "currency": "USDS", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BNB/USDS" }, { "id": "BTCUSDS", "asset": "BTC", "currency": "USDS", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/USDS" }, { "id": "USDSUSDT", "asset": "USDS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDS/USDT" }, { "id": "USDSPAX", "asset": "USDS", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDS/PAX" }, { "id": "USDSTUSD", "asset": "USDS", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDS/TUSD" }, { "id": "USDSUSDC", "asset": "USDS", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDS/USDC" }, { "id": "BTTPAX", "asset": "BTT", "currency": "PAX", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BTT/PAX" }, { "id": "BTTTUSD", "asset": "BTT", "currency": "TUSD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BTT/TUSD" }, { "id": "BTTUSDC", "asset": "BTT", "currency": "USDC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BTT/USDC" }, { "id": "ONGBNB", "asset": "ONG", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONG/BNB" }, { "id": "ONGBTC", "asset": "ONG", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ONG/BTC" }, { "id": "ONGUSDT", "asset": "ONG", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONG/USDT" }, { "id": "HOTBNB", "asset": "HOT", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "HOT/BNB" }, { "id": "HOTUSDT", "asset": "HOT", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "HOT/USDT" }, { "id": "ZILUSDT", "asset": "ZIL", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ZIL/USDT" }, { "id": "ZRXBNB", "asset": "ZRX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ZRX/BNB" }, { "id": "ZRXUSDT", "asset": "ZRX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ZRX/USDT" }, { "id": "FETBNB", "asset": "FET", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "FET/BNB" }, { "id": "FETBTC", "asset": "FET", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FET/BTC" }, { "id": "FETUSDT", "asset": "FET", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FET/USDT" }, { "id": "BATUSDT", "asset": "BAT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/USDT" }, { "id": "XMRBNB", "asset": "XMR", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "XMR/BNB" }, { "id": "XMRUSDT", "asset": "XMR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XMR/USDT" }, { "id": "ZECBNB", "asset": "ZEC", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.00100000", "label": "ZEC/BNB" }, { "id": "ZECUSDT", "asset": "ZEC", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ZEC/USDT" }, { "id": "ZECPAX", "asset": "ZEC", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ZEC/PAX" }, { "id": "ZECTUSD", "asset": "ZEC", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ZEC/TUSD" }, { "id": "ZECUSDC", "asset": "ZEC", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ZEC/USDC" }, { "id": "IOSTBNB", "asset": "IOST", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "IOST/BNB" }, { "id": "IOSTUSDT", "asset": "IOST", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "IOST/USDT" }, { "id": "CELRBNB", "asset": "CELR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "CELR/BNB" }, { "id": "CELRBTC", "asset": "CELR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CELR/BTC" }, { "id": "CELRUSDT", "asset": "CELR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CELR/USDT" }, { "id": "ADAPAX", "asset": "ADA", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ADA/PAX" }, { "id": "ADAUSDC", "asset": "ADA", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/USDC" }, { "id": "NEOPAX", "asset": "NEO", "currency": "PAX", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/PAX" }, { "id": "NEOUSDC", "asset": "NEO", "currency": "USDC", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/USDC" }, { "id": "DASHBNB", "asset": "DASH", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.00100000", "label": "DASH/BNB" }, { "id": "DASHUSDT", "asset": "DASH", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "DASH/USDT" }, { "id": "NANOUSDT", "asset": "NANO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NANO/USDT" }, { "id": "OMGBNB", "asset": "OMG", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "OMG/BNB" }, { "id": "OMGUSDT", "asset": "OMG", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OMG/USDT" }, { "id": "THETAUSDT", "asset": "THETA", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "THETA/USDT" }, { "id": "ENJUSDT", "asset": "ENJ", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ENJ/USDT" }, { "id": "MITHUSDT", "asset": "MITH", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MITH/USDT" }, { "id": "MATICBNB", "asset": "MATIC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "MATIC/BNB" }, { "id": "MATICBTC", "asset": "MATIC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MATIC/BTC" }, { "id": "MATICUSDT", "asset": "MATIC", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MATIC/USDT" }, { "id": "ATOMBNB", "asset": "ATOM", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "ATOM/BNB" }, { "id": "ATOMBTC", "asset": "ATOM", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ATOM/BTC" }, { "id": "ATOMUSDT", "asset": "ATOM", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/USDT" }, { "id": "ATOMUSDC", "asset": "ATOM", "currency": "USDC", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/USDC" }, { "id": "ATOMPAX", "asset": "ATOM", "currency": "PAX", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/PAX" }, { "id": "ATOMTUSD", "asset": "ATOM", "currency": "TUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/TUSD" }, { "id": "ETCUSDC", "asset": "ETC", "currency": "USDC", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/USDC" }, { "id": "ETCPAX", "asset": "ETC", "currency": "PAX", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/PAX" }, { "id": "ETCTUSD", "asset": "ETC", "currency": "TUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/TUSD" }, { "id": "BATUSDC", "asset": "BAT", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/USDC" }, { "id": "BATPAX", "asset": "BAT", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/PAX" }, { "id": "BATTUSD", "asset": "BAT", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/TUSD" }, { "id": "PHBBNB", "asset": "PHB", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "PHB/BNB" }, { "id": "PHBBTC", "asset": "PHB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PHB/BTC" }, { "id": "PHBUSDC", "asset": "PHB", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PHB/USDC" }, { "id": "PHBTUSD", "asset": "PHB", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PHB/TUSD" }, { "id": "PHBPAX", "asset": "PHB", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PHB/PAX" }, { "id": "TFUELBNB", "asset": "TFUEL", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "TFUEL/BNB" }, { "id": "TFUELBTC", "asset": "TFUEL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TFUEL/BTC" }, { "id": "TFUELUSDT", "asset": "TFUEL", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TFUEL/USDT" }, { "id": "TFUELUSDC", "asset": "TFUEL", "currency": "USDC", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "TFUEL/USDC" }, { "id": "TFUELTUSD", "asset": "TFUEL", "currency": "TUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "TFUEL/TUSD" }, { "id": "TFUELPAX", "asset": "TFUEL", "currency": "PAX", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "TFUEL/PAX" }, { "id": "ONEBNB", "asset": "ONE", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ONE/BNB" }, { "id": "ONEBTC", "asset": "ONE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ONE/BTC" }, { "id": "ONEUSDT", "asset": "ONE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/USDT" }, { "id": "ONETUSD", "asset": "ONE", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/TUSD" }, { "id": "ONEPAX", "asset": "ONE", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/PAX" }, { "id": "ONEUSDC", "asset": "ONE", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/USDC" }, { "id": "FTMBNB", "asset": "FTM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "FTM/BNB" }, { "id": "FTMBTC", "asset": "FTM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FTM/BTC" }, { "id": "FTMUSDT", "asset": "FTM", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FTM/USDT" }, { "id": "FTMTUSD", "asset": "FTM", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FTM/TUSD" }, { "id": "FTMPAX", "asset": "FTM", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FTM/PAX" }, { "id": "FTMUSDC", "asset": "FTM", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FTM/USDC" }, { "id": "BTCBBTC", "asset": "BTCB", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BTCB/BTC" }, { "id": "BCPTTUSD", "asset": "BCPT", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BCPT/TUSD" }, { "id": "BCPTPAX", "asset": "BCPT", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BCPT/PAX" }, { "id": "BCPTUSDC", "asset": "BCPT", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BCPT/USDC" }, { "id": "ALGOBNB", "asset": "ALGO", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "ALGO/BNB" }, { "id": "ALGOBTC", "asset": "ALGO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ALGO/BTC" }, { "id": "ALGOUSDT", "asset": "ALGO", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/USDT" }, { "id": "ALGOTUSD", "asset": "ALGO", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/TUSD" }, { "id": "ALGOPAX", "asset": "ALGO", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/PAX" }, { "id": "ALGOUSDC", "asset": "ALGO", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/USDC" }, { "id": "USDSBUSDT", "asset": "USDSB", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDSB/USDT" }, { "id": "USDSBUSDS", "asset": "USDSB", "currency": "USDS", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDSB/USDS" }, { "id": "GTOUSDT", "asset": "GTO", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "GTO/USDT" }, { "id": "GTOPAX", "asset": "GTO", "currency": "PAX", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "GTO/PAX" }, { "id": "GTOTUSD", "asset": "GTO", "currency": "TUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "GTO/TUSD" }, { "id": "GTOUSDC", "asset": "GTO", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "GTO/USDC" }, { "id": "ERDBNB", "asset": "ERD", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ERD/BNB" }, { "id": "ERDBTC", "asset": "ERD", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ERD/BTC" }, { "id": "ERDUSDT", "asset": "ERD", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ERD/USDT" }, { "id": "ERDPAX", "asset": "ERD", "currency": "PAX", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ERD/PAX" }, { "id": "ERDUSDC", "asset": "ERD", "currency": "USDC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ERD/USDC" }, { "id": "DOGEBNB", "asset": "DOGE", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DOGE/BNB" }, { "id": "DOGEBTC", "asset": "DOGE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DOGE/BTC" }, { "id": "DOGEUSDT", "asset": "DOGE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOGE/USDT" }, { "id": "DOGEPAX", "asset": "DOGE", "currency": "PAX", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DOGE/PAX" }, { "id": "DOGEUSDC", "asset": "DOGE", "currency": "USDC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DOGE/USDC" }, { "id": "DUSKBNB", "asset": "DUSK", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DUSK/BNB" }, { "id": "DUSKBTC", "asset": "DUSK", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DUSK/BTC" }, { "id": "DUSKUSDT", "asset": "DUSK", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DUSK/USDT" }, { "id": "DUSKUSDC", "asset": "DUSK", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DUSK/USDC" }, { "id": "DUSKPAX", "asset": "DUSK", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DUSK/PAX" }, { "id": "BGBPUSDC", "asset": "BGBP", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BGBP/USDC" }, { "id": "ANKRBNB", "asset": "ANKR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ANKR/BNB" }, { "id": "ANKRBTC", "asset": "ANKR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ANKR/BTC" }, { "id": "ANKRUSDT", "asset": "ANKR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ANKR/USDT" }, { "id": "ANKRTUSD", "asset": "ANKR", "currency": "TUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ANKR/TUSD" }, { "id": "ANKRPAX", "asset": "ANKR", "currency": "PAX", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ANKR/PAX" }, { "id": "ANKRUSDC", "asset": "ANKR", "currency": "USDC", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ANKR/USDC" }, { "id": "ONTPAX", "asset": "ONT", "currency": "PAX", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONT/PAX" }, { "id": "ONTUSDC", "asset": "ONT", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONT/USDC" }, { "id": "WINBNB", "asset": "WIN", "currency": "BNB", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WIN/BNB" }, { "id": "WINBTC", "asset": "WIN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WIN/BTC" }, { "id": "WINUSDT", "asset": "WIN", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "WIN/USDT" }, { "id": "WINUSDC", "asset": "WIN", "currency": "USDC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "WIN/USDC" }, { "id": "COSBNB", "asset": "COS", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "COS/BNB" }, { "id": "COSBTC", "asset": "COS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "COS/BTC" }, { "id": "COSUSDT", "asset": "COS", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "COS/USDT" }, { "id": "TUSDBTUSD", "asset": "TUSDB", "currency": "TUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TUSDB/TUSD" }, { "id": "NPXSUSDT", "asset": "NPXS", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "NPXS/USDT" }, { "id": "NPXSUSDC", "asset": "NPXS", "currency": "USDC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "NPXS/USDC" }, { "id": "COCOSBNB", "asset": "COCOS", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "COCOS/BNB" }, { "id": "COCOSBTC", "asset": "COCOS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "COCOS/BTC" }, { "id": "COCOSUSDT", "asset": "COCOS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "COCOS/USDT" }, { "id": "MTLUSDT", "asset": "MTL", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MTL/USDT" }, { "id": "TOMOBNB", "asset": "TOMO", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TOMO/BNB" }, { "id": "TOMOBTC", "asset": "TOMO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TOMO/BTC" }, { "id": "TOMOUSDT", "asset": "TOMO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TOMO/USDT" }, { "id": "TOMOUSDC", "asset": "TOMO", "currency": "USDC", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TOMO/USDC" }, { "id": "PERLBNB", "asset": "PERL", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "PERL/BNB" }, { "id": "PERLBTC", "asset": "PERL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PERL/BTC" }, { "id": "PERLUSDC", "asset": "PERL", "currency": "USDC", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PERL/USDC" }, { "id": "PERLUSDT", "asset": "PERL", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PERL/USDT" }, { "id": "DENTUSDT", "asset": "DENT", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DENT/USDT" }, { "id": "MFTUSDT", "asset": "MFT", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "MFT/USDT" }, { "id": "KEYUSDT", "asset": "KEY", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "KEY/USDT" }, { "id": "STORMUSDT", "asset": "STORM", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "STORM/USDT" }, { "id": "DOCKUSDT", "asset": "DOCK", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "DOCK/USDT" }, { "id": "WANUSDT", "asset": "WAN", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WAN/USDT" }, { "id": "FUNUSDT", "asset": "FUN", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "FUN/USDT" }, { "id": "CVCUSDT", "asset": "CVC", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CVC/USDT" }, { "id": "BTTTRX", "asset": "BTT", "currency": "TRX", "min_size": "0.10000000", "max_size": "92141578.00000000", "min_total": "100.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BTT/TRX" }, { "id": "WINTRX", "asset": "WIN", "currency": "TRX", "min_size": "0.10000000", "max_size": "92141578.00000000", "min_total": "100.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "WIN/TRX" }, { "id": "CHZBNB", "asset": "CHZ", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "CHZ/BNB" }, { "id": "CHZBTC", "asset": "CHZ", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CHZ/BTC" }, { "id": "CHZUSDT", "asset": "CHZ", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CHZ/USDT" }, { "id": "BANDBNB", "asset": "BAND", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BAND/BNB" }, { "id": "BANDBTC", "asset": "BAND", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "BAND/BTC" }, { "id": "BANDUSDT", "asset": "BAND", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAND/USDT" }, { "id": "BNBBUSD", "asset": "BNB", "currency": "BUSD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/BUSD" }, { "id": "BTCBUSD", "asset": "BTC", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/BUSD" }, { "id": "BUSDUSDT", "asset": "BUSD", "currency": "USDT", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BUSD/USDT" }, { "id": "BEAMBNB", "asset": "BEAM", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BEAM/BNB" }, { "id": "BEAMBTC", "asset": "BEAM", "currency": "BTC", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "BEAM/BTC" }, { "id": "BEAMUSDT", "asset": "BEAM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BEAM/USDT" }, { "id": "XTZBNB", "asset": "XTZ", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XTZ/BNB" }, { "id": "XTZBTC", "asset": "XTZ", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "XTZ/BTC" }, { "id": "XTZUSDT", "asset": "XTZ", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XTZ/USDT" }, { "id": "RENUSDT", "asset": "REN", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "REN/USDT" }, { "id": "RVNUSDT", "asset": "RVN", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RVN/USDT" }, { "id": "HCUSDT", "asset": "HC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "HC/USDT" }, { "id": "HBARBNB", "asset": "HBAR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "HBAR/BNB" }, { "id": "HBARBTC", "asset": "HBAR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "HBAR/BTC" }, { "id": "HBARUSDT", "asset": "HBAR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HBAR/USDT" }, { "id": "NKNBNB", "asset": "NKN", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "NKN/BNB" }, { "id": "NKNBTC", "asset": "NKN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NKN/BTC" }, { "id": "NKNUSDT", "asset": "NKN", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NKN/USDT" }, { "id": "XRPBUSD", "asset": "XRP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/BUSD" }, { "id": "ETHBUSD", "asset": "ETH", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/BUSD" }, { "id": "BCHABCBUSD", "asset": "BCH", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/BUSD" }, { "id": "LTCBUSD", "asset": "LTC", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/BUSD" }, { "id": "LINKBUSD", "asset": "LINK", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/BUSD" }, { "id": "ETCBUSD", "asset": "ETC", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/BUSD" }, { "id": "STXBNB", "asset": "STX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "STX/BNB" }, { "id": "STXBTC", "asset": "STX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STX/BTC" }, { "id": "STXUSDT", "asset": "STX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STX/USDT" }, { "id": "KAVABNB", "asset": "KAVA", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "KAVA/BNB" }, { "id": "KAVABTC", "asset": "KAVA", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "KAVA/BTC" }, { "id": "KAVAUSDT", "asset": "KAVA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "KAVA/USDT" }, { "id": "BUSDNGN", "asset": "BUSD", "currency": "NGN", "min_size": "0.01000000", "max_size": "922320.00000000", "min_total": "500.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "BUSD/NGN" }, { "id": "BNBNGN", "asset": "BNB", "currency": "NGN", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00100000", "label": "BNB/NGN" }, { "id": "BTCNGN", "asset": "BTC", "currency": "NGN", "min_size": "0.00000100", "max_size": "921.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/NGN" }, { "id": "ARPABNB", "asset": "ARPA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ARPA/BNB" }, { "id": "ARPABTC", "asset": "ARPA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ARPA/BTC" }, { "id": "ARPAUSDT", "asset": "ARPA", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ARPA/USDT" }, { "id": "TRXBUSD", "asset": "TRX", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "TRX/BUSD" }, { "id": "EOSBUSD", "asset": "EOS", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/BUSD" }, { "id": "IOTXUSDT", "asset": "IOTX", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "IOTX/USDT" }, { "id": "RLCUSDT", "asset": "RLC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "RLC/USDT" }, { "id": "MCOUSDT", "asset": "MCO", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "MCO/USDT" }, { "id": "XLMBUSD", "asset": "XLM", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/BUSD" }, { "id": "ADABUSD", "asset": "ADA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/BUSD" }, { "id": "CTXCBNB", "asset": "CTXC", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CTXC/BNB" }, { "id": "CTXCBTC", "asset": "CTXC", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CTXC/BTC" }, { "id": "CTXCUSDT", "asset": "CTXC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CTXC/USDT" }, { "id": "BCHBNB", "asset": "BCH", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BCH/BNB" }, { "id": "BCHBTC", "asset": "BCH", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BCH/BTC" }, { "id": "BCHUSDT", "asset": "BCH", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/USDT" }, { "id": "BCHUSDC", "asset": "BCH", "currency": "USDC", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/USDC" }, { "id": "BCHTUSD", "asset": "BCH", "currency": "TUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/TUSD" }, { "id": "BCHPAX", "asset": "BCH", "currency": "PAX", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/PAX" }, { "id": "BCHBUSD", "asset": "BCH", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/BUSD" }, { "id": "BTCRUB", "asset": "BTC", "currency": "RUB", "min_size": "0.00000100", "max_size": "900.00000000", "min_total": "100.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/RUB" }, { "id": "ETHRUB", "asset": "ETH", "currency": "RUB", "min_size": "0.00001000", "max_size": "92232.00000000", "min_total": "100.00000000", "increment": "0.10000000", "asset_increment": "0.00001000", "label": "ETH/RUB" }, { "id": "XRPRUB", "asset": "XRP", "currency": "RUB", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "XRP/RUB" }, { "id": "BNBRUB", "asset": "BNB", "currency": "RUB", "min_size": "0.00100000", "max_size": "922327.00000000", "min_total": "100.00000000", "increment": "0.01000000", "asset_increment": "0.00100000", "label": "BNB/RUB" }, { "id": "TROYBNB", "asset": "TROY", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TROY/BNB" }, { "id": "TROYBTC", "asset": "TROY", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TROY/BTC" }, { "id": "TROYUSDT", "asset": "TROY", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "TROY/USDT" }, { "id": "BUSDRUB", "asset": "BUSD", "currency": "RUB", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "BUSD/RUB" }, { "id": "QTUMBUSD", "asset": "QTUM", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "QTUM/BUSD" }, { "id": "VETBUSD", "asset": "VET", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "VET/BUSD" }, { "id": "VITEBNB", "asset": "VITE", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "VITE/BNB" }, { "id": "VITEBTC", "asset": "VITE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VITE/BTC" }, { "id": "VITEUSDT", "asset": "VITE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "VITE/USDT" }, { "id": "FTTBNB", "asset": "FTT", "currency": "BNB", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FTT/BNB" }, { "id": "FTTBTC", "asset": "FTT", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "FTT/BTC" }, { "id": "FTTUSDT", "asset": "FTT", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FTT/USDT" }, { "id": "BTCTRY", "asset": "BTC", "currency": "TRY", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/TRY" }, { "id": "BNBTRY", "asset": "BNB", "currency": "TRY", "min_size": "0.00100000", "max_size": "92232.00000000", "min_total": "10.00000000", "increment": "1.00000000", "asset_increment": "0.00100000", "label": "BNB/TRY" }, { "id": "BUSDTRY", "asset": "BUSD", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "BUSD/TRY" }, { "id": "ETHTRY", "asset": "ETH", "currency": "TRY", "min_size": "0.00000100", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "ETH/TRY" }, { "id": "XRPTRY", "asset": "XRP", "currency": "TRY", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XRP/TRY" }, { "id": "USDTTRY", "asset": "USDT", "currency": "TRY", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "USDT/TRY" }, { "id": "USDTRUB", "asset": "USDT", "currency": "RUB", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "USDT/RUB" }, { "id": "BTCEUR", "asset": "BTC", "currency": "EUR", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/EUR" }, { "id": "ETHEUR", "asset": "ETH", "currency": "EUR", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/EUR" }, { "id": "BNBEUR", "asset": "BNB", "currency": "EUR", "min_size": "0.00010000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/EUR" }, { "id": "XRPEUR", "asset": "XRP", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/EUR" }, { "id": "EURBUSD", "asset": "EUR", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EUR/BUSD" }, { "id": "EURUSDT", "asset": "EUR", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EUR/USDT" }, { "id": "OGNBNB", "asset": "OGN", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "OGN/BNB" }, { "id": "OGNBTC", "asset": "OGN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OGN/BTC" }, { "id": "OGNUSDT", "asset": "OGN", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OGN/USDT" }, { "id": "DREPBNB", "asset": "DREP", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DREP/BNB" }, { "id": "DREPBTC", "asset": "DREP", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "DREP/BTC" }, { "id": "DREPUSDT", "asset": "DREP", "currency": "USDT", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DREP/USDT" }, { "id": "BULLUSDT", "asset": "BULL", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BULL/USDT" }, { "id": "BULLBUSD", "asset": "BULL", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BULL/BUSD" }, { "id": "BEARUSDT", "asset": "BEAR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BEAR/USDT" }, { "id": "BEARBUSD", "asset": "BEAR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BEAR/BUSD" }, { "id": "ETHBULLUSDT", "asset": "ETHBULL", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "ETHBULL/USDT" }, { "id": "ETHBULLBUSD", "asset": "ETHBULL", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "ETHBULL/BUSD" }, { "id": "ETHBEARUSDT", "asset": "ETHBEAR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETHBEAR/USDT" }, { "id": "ETHBEARBUSD", "asset": "ETHBEAR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETHBEAR/BUSD" }, { "id": "TCTBNB", "asset": "TCT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "TCT/BNB" }, { "id": "TCTBTC", "asset": "TCT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TCT/BTC" }, { "id": "TCTUSDT", "asset": "TCT", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "TCT/USDT" }, { "id": "WRXBNB", "asset": "WRX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "WRX/BNB" }, { "id": "WRXBTC", "asset": "WRX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "WRX/BTC" }, { "id": "WRXUSDT", "asset": "WRX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WRX/USDT" }, { "id": "ICXBUSD", "asset": "ICX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ICX/BUSD" }, { "id": "BTSUSDT", "asset": "BTS", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BTS/USDT" }, { "id": "BTSBUSD", "asset": "BTS", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BTS/BUSD" }, { "id": "LSKUSDT", "asset": "LSK", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LSK/USDT" }, { "id": "BNTUSDT", "asset": "BNT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BNT/USDT" }, { "id": "BNTBUSD", "asset": "BNT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BNT/BUSD" }, { "id": "LTOBNB", "asset": "LTO", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "LTO/BNB" }, { "id": "LTOBTC", "asset": "LTO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LTO/BTC" }, { "id": "LTOUSDT", "asset": "LTO", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LTO/USDT" }, { "id": "ATOMBUSD", "asset": "ATOM", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/BUSD" }, { "id": "DASHBUSD", "asset": "DASH", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "DASH/BUSD" }, { "id": "NEOBUSD", "asset": "NEO", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/BUSD" }, { "id": "WAVESBUSD", "asset": "WAVES", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WAVES/BUSD" }, { "id": "XTZBUSD", "asset": "XTZ", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XTZ/BUSD" }, { "id": "EOSBULLUSDT", "asset": "EOSBULL", "currency": "USDT", "min_size": "0.00001000", "max_size": "92232.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "EOSBULL/USDT" }, { "id": "EOSBULLBUSD", "asset": "EOSBULL", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "EOSBULL/BUSD" }, { "id": "EOSBEARUSDT", "asset": "EOSBEAR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "EOSBEAR/USDT" }, { "id": "EOSBEARBUSD", "asset": "EOSBEAR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "EOSBEAR/BUSD" }, { "id": "XRPBULLUSDT", "asset": "XRPBULL", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XRPBULL/USDT" }, { "id": "XRPBULLBUSD", "asset": "XRPBULL", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XRPBULL/BUSD" }, { "id": "XRPBEARUSDT", "asset": "XRPBEAR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XRPBEAR/USDT" }, { "id": "XRPBEARBUSD", "asset": "XRPBEAR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XRPBEAR/BUSD" }, { "id": "BATBUSD", "asset": "BAT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/BUSD" }, { "id": "ENJBUSD", "asset": "ENJ", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ENJ/BUSD" }, { "id": "NANOBUSD", "asset": "NANO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NANO/BUSD" }, { "id": "ONTBUSD", "asset": "ONT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONT/BUSD" }, { "id": "RVNBUSD", "asset": "RVN", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RVN/BUSD" }, { "id": "STRATBUSD", "asset": "STRAT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STRAT/BUSD" }, { "id": "STRATBNB", "asset": "STRAT", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "STRAT/BNB" }, { "id": "STRATUSDT", "asset": "STRAT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STRAT/USDT" }, { "id": "AIONBUSD", "asset": "AION", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AION/BUSD" }, { "id": "AIONUSDT", "asset": "AION", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AION/USDT" }, { "id": "MBLBNB", "asset": "MBL", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MBL/BNB" }, { "id": "MBLBTC", "asset": "MBL", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MBL/BTC" }, { "id": "MBLUSDT", "asset": "MBL", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "MBL/USDT" }, { "id": "COTIBNB", "asset": "COTI", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "COTI/BNB" }, { "id": "COTIBTC", "asset": "COTI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "COTI/BTC" }, { "id": "COTIUSDT", "asset": "COTI", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "COTI/USDT" }, { "id": "ALGOBUSD", "asset": "ALGO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/BUSD" }, { "id": "BTTBUSD", "asset": "BTT", "currency": "BUSD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BTT/BUSD" }, { "id": "TOMOBUSD", "asset": "TOMO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TOMO/BUSD" }, { "id": "XMRBUSD", "asset": "XMR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "XMR/BUSD" }, { "id": "ZECBUSD", "asset": "ZEC", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ZEC/BUSD" }, { "id": "BNBBULLUSDT", "asset": "BNBBULL", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BNBBULL/USDT" }, { "id": "BNBBULLBUSD", "asset": "BNBBULL", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BNBBULL/BUSD" }, { "id": "BNBBEARUSDT", "asset": "BNBBEAR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BNBBEAR/USDT" }, { "id": "BNBBEARBUSD", "asset": "BNBBEAR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BNBBEAR/BUSD" }, { "id": "STPTBNB", "asset": "STPT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "STPT/BNB" }, { "id": "STPTBTC", "asset": "STPT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STPT/BTC" }, { "id": "STPTUSDT", "asset": "STPT", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "STPT/USDT" }, { "id": "BTCZAR", "asset": "BTC", "currency": "ZAR", "min_size": "0.00000100", "max_size": "9214.00000000", "min_total": "100.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/ZAR" }, { "id": "ETHZAR", "asset": "ETH", "currency": "ZAR", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "100.00000000", "increment": "0.10000000", "asset_increment": "0.00001000", "label": "ETH/ZAR" }, { "id": "BNBZAR", "asset": "BNB", "currency": "ZAR", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "BNB/ZAR" }, { "id": "USDTZAR", "asset": "USDT", "currency": "ZAR", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "USDT/ZAR" }, { "id": "BUSDZAR", "asset": "BUSD", "currency": "ZAR", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "BUSD/ZAR" }, { "id": "BTCBKRW", "asset": "BTC", "currency": "BKRW", "min_size": "0.00000100", "max_size": "100.00000000", "min_total": "1000.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/BKRW" }, { "id": "ETHBKRW", "asset": "ETH", "currency": "BKRW", "min_size": "0.00001000", "max_size": "8000.00000000", "min_total": "1000.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "ETH/BKRW" }, { "id": "BNBBKRW", "asset": "BNB", "currency": "BKRW", "min_size": "0.00100000", "max_size": "9000.00000000", "min_total": "1000.00000000", "increment": "1.00000000", "asset_increment": "0.00100000", "label": "BNB/BKRW" }, { "id": "WTCUSDT", "asset": "WTC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WTC/USDT" }, { "id": "DATABUSD", "asset": "DATA", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DATA/BUSD" }, { "id": "DATAUSDT", "asset": "DATA", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DATA/USDT" }, { "id": "XZCUSDT", "asset": "XZC", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "XZC/USDT" }, { "id": "SOLBNB", "asset": "SOL", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SOL/BNB" }, { "id": "SOLBTC", "asset": "SOL", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "SOL/BTC" }, { "id": "SOLUSDT", "asset": "SOL", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SOL/USDT" }, { "id": "SOLBUSD", "asset": "SOL", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SOL/BUSD" }, { "id": "BTCIDRT", "asset": "BTC", "currency": "IDRT", "min_size": "0.00000100", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00000100", "label": "BTC/IDRT" }, { "id": "BNBIDRT", "asset": "BNB", "currency": "IDRT", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00100000", "label": "BNB/IDRT" }, { "id": "USDTIDRT", "asset": "USDT", "currency": "IDRT", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "USDT/IDRT" }, { "id": "BUSDIDRT", "asset": "BUSD", "currency": "IDRT", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "BUSD/IDRT" }, { "id": "CTSIBTC", "asset": "CTSI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CTSI/BTC" }, { "id": "CTSIUSDT", "asset": "CTSI", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CTSI/USDT" }, { "id": "CTSIBNB", "asset": "CTSI", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CTSI/BNB" }, { "id": "CTSIBUSD", "asset": "CTSI", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CTSI/BUSD" }, { "id": "HIVEBNB", "asset": "HIVE", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HIVE/BNB" }, { "id": "HIVEBTC", "asset": "HIVE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "HIVE/BTC" }, { "id": "HIVEUSDT", "asset": "HIVE", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "HIVE/USDT" }, { "id": "CHRBNB", "asset": "CHR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "CHR/BNB" }, { "id": "CHRBTC", "asset": "CHR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CHR/BTC" }, { "id": "CHRUSDT", "asset": "CHR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CHR/USDT" }, { "id": "BTCUPUSDT", "asset": "BTCUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BTCUP/USDT" }, { "id": "BTCDOWNUSDT", "asset": "BTCDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "921415.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "BTCDOWN/USDT" }, { "id": "GXSUSDT", "asset": "GXS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GXS/USDT" }, { "id": "ARDRUSDT", "asset": "ARDR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ARDR/USDT" }, { "id": "ERDBUSD", "asset": "ERD", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ERD/BUSD" }, { "id": "LENDUSDT", "asset": "LEND", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LEND/USDT" }, { "id": "HBARBUSD", "asset": "HBAR", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HBAR/BUSD" }, { "id": "MATICBUSD", "asset": "MATIC", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MATIC/BUSD" }, { "id": "WRXBUSD", "asset": "WRX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WRX/BUSD" }, { "id": "ZILBUSD", "asset": "ZIL", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ZIL/BUSD" }, { "id": "MDTBNB", "asset": "MDT", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "MDT/BNB" }, { "id": "MDTBTC", "asset": "MDT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "MDT/BTC" }, { "id": "MDTUSDT", "asset": "MDT", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MDT/USDT" }, { "id": "STMXBNB", "asset": "STMX", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "STMX/BNB" }, { "id": "STMXBTC", "asset": "STMX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STMX/BTC" }, { "id": "STMXETH", "asset": "STMX", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "STMX/ETH" }, { "id": "STMXUSDT", "asset": "STMX", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "STMX/USDT" }, { "id": "KNCBUSD", "asset": "KNC", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "KNC/BUSD" }, { "id": "KNCUSDT", "asset": "KNC", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "KNC/USDT" }, { "id": "REPBUSD", "asset": "REP", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "REP/BUSD" }, { "id": "REPUSDT", "asset": "REP", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "REP/USDT" }, { "id": "LRCBUSD", "asset": "LRC", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LRC/BUSD" }, { "id": "LRCUSDT", "asset": "LRC", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LRC/USDT" }, { "id": "IQBNB", "asset": "IQ", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IQ/BNB" }, { "id": "IQBUSD", "asset": "IQ", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "IQ/BUSD" }, { "id": "PNTBTC", "asset": "PNT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PNT/BTC" }, { "id": "PNTUSDT", "asset": "PNT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "PNT/USDT" }, { "id": "BTCGBP", "asset": "BTC", "currency": "GBP", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/GBP" }, { "id": "ETHGBP", "asset": "ETH", "currency": "GBP", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/GBP" }, { "id": "XRPGBP", "asset": "XRP", "currency": "GBP", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XRP/GBP" }, { "id": "BNBGBP", "asset": "BNB", "currency": "GBP", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/GBP" }, { "id": "GBPBUSD", "asset": "GBP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GBP/BUSD" }, { "id": "DGBBNB", "asset": "DGB", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DGB/BNB" }, { "id": "DGBBTC", "asset": "DGB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DGB/BTC" }, { "id": "DGBBUSD", "asset": "DGB", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DGB/BUSD" }, { "id": "BTCUAH", "asset": "BTC", "currency": "UAH", "min_size": "0.00000100", "max_size": "1800.00000000", "min_total": "100.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/UAH" }, { "id": "USDTUAH", "asset": "USDT", "currency": "UAH", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "USDT/UAH" }, { "id": "COMPBTC", "asset": "COMP", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "COMP/BTC" }, { "id": "COMPBNB", "asset": "COMP", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "COMP/BNB" }, { "id": "COMPBUSD", "asset": "COMP", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "COMP/BUSD" }, { "id": "COMPUSDT", "asset": "COMP", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "COMP/USDT" }, { "id": "BTCBIDR", "asset": "BTC", "currency": "BIDR", "min_size": "0.00000100", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00000100", "label": "BTC/BIDR" }, { "id": "ETHBIDR", "asset": "ETH", "currency": "BIDR", "min_size": "0.00001000", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00001000", "label": "ETH/BIDR" }, { "id": "BNBBIDR", "asset": "BNB", "currency": "BIDR", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00100000", "label": "BNB/BIDR" }, { "id": "BUSDBIDR", "asset": "BUSD", "currency": "BIDR", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "BUSD/BIDR" }, { "id": "USDTBIDR", "asset": "USDT", "currency": "BIDR", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "USDT/BIDR" }, { "id": "BKRWUSDT", "asset": "BKRW", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BKRW/USDT" }, { "id": "BKRWBUSD", "asset": "BKRW", "currency": "BUSD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "BKRW/BUSD" }, { "id": "SCUSDT", "asset": "SC", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "SC/USDT" }, { "id": "ZENUSDT", "asset": "ZEN", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "ZEN/USDT" }, { "id": "SXPBTC", "asset": "SXP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SXP/BTC" }, { "id": "SXPBNB", "asset": "SXP", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SXP/BNB" }, { "id": "SXPBUSD", "asset": "SXP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SXP/BUSD" }, { "id": "SNXBTC", "asset": "SNX", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "SNX/BTC" }, { "id": "SNXBNB", "asset": "SNX", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "SNX/BNB" }, { "id": "SNXBUSD", "asset": "SNX", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SNX/BUSD" }, { "id": "SNXUSDT", "asset": "SNX", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SNX/USDT" }, { "id": "ETHUPUSDT", "asset": "ETHUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "ETHUP/USDT" }, { "id": "ETHDOWNUSDT", "asset": "ETHDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ETHDOWN/USDT" }, { "id": "ADAUPUSDT", "asset": "ADAUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "ADAUP/USDT" }, { "id": "ADADOWNUSDT", "asset": "ADADOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADADOWN/USDT" }, { "id": "LINKUPUSDT", "asset": "LINKUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "LINKUP/USDT" }, { "id": "LINKDOWNUSDT", "asset": "LINKDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LINKDOWN/USDT" }, { "id": "VTHOBNB", "asset": "VTHO", "currency": "BNB", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.05000000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VTHO/BNB" }, { "id": "VTHOBUSD", "asset": "VTHO", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "VTHO/BUSD" }, { "id": "VTHOUSDT", "asset": "VTHO", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "VTHO/USDT" }, { "id": "DCRBUSD", "asset": "DCR", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DCR/BUSD" }, { "id": "DGBUSDT", "asset": "DGB", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DGB/USDT" }, { "id": "GBPUSDT", "asset": "GBP", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GBP/USDT" }, { "id": "STORJBUSD", "asset": "STORJ", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STORJ/BUSD" }, { "id": "SXPUSDT", "asset": "SXP", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SXP/USDT" }, { "id": "IRISBNB", "asset": "IRIS", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "IRIS/BNB" }, { "id": "IRISBTC", "asset": "IRIS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IRIS/BTC" }, { "id": "IRISBUSD", "asset": "IRIS", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "IRIS/BUSD" }, { "id": "MKRBNB", "asset": "MKR", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "MKR/BNB" }, { "id": "MKRBTC", "asset": "MKR", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "MKR/BTC" }, { "id": "MKRUSDT", "asset": "MKR", "currency": "USDT", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "MKR/USDT" }, { "id": "MKRBUSD", "asset": "MKR", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "MKR/BUSD" }, { "id": "DAIBNB", "asset": "DAI", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DAI/BNB" }, { "id": "DAIBTC", "asset": "DAI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "DAI/BTC" }, { "id": "DAIUSDT", "asset": "DAI", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DAI/USDT" }, { "id": "DAIBUSD", "asset": "DAI", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DAI/BUSD" }, { "id": "RUNEBNB", "asset": "RUNE", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RUNE/BNB" }, { "id": "RUNEBTC", "asset": "RUNE", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "RUNE/BTC" }, { "id": "RUNEBUSD", "asset": "RUNE", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "RUNE/BUSD" }, { "id": "MANABUSD", "asset": "MANA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MANA/BUSD" }, { "id": "DOGEBUSD", "asset": "DOGE", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOGE/BUSD" }, { "id": "LENDBUSD", "asset": "LEND", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LEND/BUSD" }, { "id": "ZRXBUSD", "asset": "ZRX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ZRX/BUSD" }, { "id": "DCRUSDT", "asset": "DCR", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "DCR/USDT" }, { "id": "STORJUSDT", "asset": "STORJ", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STORJ/USDT" }, { "id": "XRPBKRW", "asset": "XRP", "currency": "BKRW", "min_size": "0.10000000", "max_size": "922327.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "XRP/BKRW" }, { "id": "ADABKRW", "asset": "ADA", "currency": "BKRW", "min_size": "0.10000000", "max_size": "922327.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "ADA/BKRW" }, { "id": "BTCAUD", "asset": "BTC", "currency": "AUD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/AUD" }, { "id": "ETHAUD", "asset": "ETH", "currency": "AUD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/AUD" }, { "id": "AUDBUSD", "asset": "AUD", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AUD/BUSD" }, { "id": "FIOBNB", "asset": "FIO", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "0.10000000", "label": "FIO/BNB" }, { "id": "FIOBTC", "asset": "FIO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FIO/BTC" }, { "id": "FIOBUSD", "asset": "FIO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FIO/BUSD" }, { "id": "BNBUPUSDT", "asset": "BNBUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BNBUP/USDT" }, { "id": "BNBDOWNUSDT", "asset": "BNBDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BNBDOWN/USDT" }, { "id": "XTZUPUSDT", "asset": "XTZUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XTZUP/USDT" }, { "id": "XTZDOWNUSDT", "asset": "XTZDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "XTZDOWN/USDT" }, { "id": "AVABNB", "asset": "AVA", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AVA/BNB" }, { "id": "AVABTC", "asset": "AVA", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "AVA/BTC" }, { "id": "AVABUSD", "asset": "AVA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AVA/BUSD" }, { "id": "USDTBKRW", "asset": "USDT", "currency": "BKRW", "min_size": "0.10000000", "max_size": "922327.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "USDT/BKRW" }, { "id": "BUSDBKRW", "asset": "BUSD", "currency": "BKRW", "min_size": "0.10000000", "max_size": "922327.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "BUSD/BKRW" }, { "id": "IOTABUSD", "asset": "IOTA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "IOTA/BUSD" }, { "id": "MANAUSDT", "asset": "MANA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MANA/USDT" }, { "id": "XRPAUD", "asset": "XRP", "currency": "AUD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XRP/AUD" }, { "id": "BNBAUD", "asset": "BNB", "currency": "AUD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/AUD" }, { "id": "AUDUSDT", "asset": "AUD", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AUD/USDT" }, { "id": "BALBNB", "asset": "BAL", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAL/BNB" }, { "id": "BALBTC", "asset": "BAL", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "BAL/BTC" }, { "id": "BALBUSD", "asset": "BAL", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAL/BUSD" }, { "id": "YFIBNB", "asset": "YFI", "currency": "BNB", "min_size": "0.00010000", "max_size": "10000.00000000", "min_total": "0.05000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "YFI/BNB" }, { "id": "YFIBTC", "asset": "YFI", "currency": "BTC", "min_size": "0.00010000", "max_size": "9000.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00010000", "label": "YFI/BTC" }, { "id": "YFIBUSD", "asset": "YFI", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "YFI/BUSD" }, { "id": "YFIUSDT", "asset": "YFI", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "YFI/USDT" }, { "id": "BLZBUSD", "asset": "BLZ", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BLZ/BUSD" }, { "id": "KMDBUSD", "asset": "KMD", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "KMD/BUSD" }, { "id": "BALUSDT", "asset": "BAL", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAL/USDT" }, { "id": "BLZUSDT", "asset": "BLZ", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BLZ/USDT" }, { "id": "IRISUSDT", "asset": "IRIS", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "IRIS/USDT" }, { "id": "KMDUSDT", "asset": "KMD", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "KMD/USDT" }, { "id": "BTCDAI", "asset": "BTC", "currency": "DAI", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/DAI" }, { "id": "ETHDAI", "asset": "ETH", "currency": "DAI", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/DAI" }, { "id": "BNBDAI", "asset": "BNB", "currency": "DAI", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "BNB/DAI" }, { "id": "USDTDAI", "asset": "USDT", "currency": "DAI", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDT/DAI" }, { "id": "BUSDDAI", "asset": "BUSD", "currency": "DAI", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BUSD/DAI" }, { "id": "JSTBNB", "asset": "JST", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "JST/BNB" }, { "id": "JSTBTC", "asset": "JST", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "JST/BTC" }, { "id": "JSTBUSD", "asset": "JST", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "JST/BUSD" }, { "id": "JSTUSDT", "asset": "JST", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "JST/USDT" }, { "id": "SRMBNB", "asset": "SRM", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "SRM/BNB" }, { "id": "SRMBTC", "asset": "SRM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SRM/BTC" }, { "id": "SRMBUSD", "asset": "SRM", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SRM/BUSD" }, { "id": "SRMUSDT", "asset": "SRM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SRM/USDT" }, { "id": "ANTBNB", "asset": "ANT", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "ANT/BNB" }, { "id": "ANTBTC", "asset": "ANT", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ANT/BTC" }, { "id": "ANTBUSD", "asset": "ANT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ANT/BUSD" }, { "id": "ANTUSDT", "asset": "ANT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ANT/USDT" }, { "id": "CRVBNB", "asset": "CRV", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "CRV/BNB" }, { "id": "CRVBTC", "asset": "CRV", "currency": "BTC", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "CRV/BTC" }, { "id": "CRVBUSD", "asset": "CRV", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CRV/BUSD" }, { "id": "CRVUSDT", "asset": "CRV", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CRV/USDT" }, { "id": "SANDBNB", "asset": "SAND", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "SAND/BNB" }, { "id": "SANDBTC", "asset": "SAND", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SAND/BTC" }, { "id": "SANDUSDT", "asset": "SAND", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SAND/USDT" }, { "id": "SANDBUSD", "asset": "SAND", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SAND/BUSD" }, { "id": "OCEANBNB", "asset": "OCEAN", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "OCEAN/BNB" }, { "id": "OCEANBTC", "asset": "OCEAN", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OCEAN/BTC" }, { "id": "OCEANBUSD", "asset": "OCEAN", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OCEAN/BUSD" }, { "id": "OCEANUSDT", "asset": "OCEAN", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OCEAN/USDT" }, { "id": "NMRBNB", "asset": "NMR", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NMR/BNB" }, { "id": "NMRBTC", "asset": "NMR", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "NMR/BTC" }, { "id": "NMRBUSD", "asset": "NMR", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NMR/BUSD" }, { "id": "NMRUSDT", "asset": "NMR", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NMR/USDT" }, { "id": "DOTBNB", "asset": "DOT", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOT/BNB" }, { "id": "DOTBTC", "asset": "DOT", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "DOT/BTC" }, { "id": "DOTBUSD", "asset": "DOT", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DOT/BUSD" }, { "id": "DOTUSDT", "asset": "DOT", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DOT/USDT" }, { "id": "LUNABNB", "asset": "LUNA", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LUNA/BNB" }, { "id": "LUNABTC", "asset": "LUNA", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "LUNA/BTC" }, { "id": "LUNABUSD", "asset": "LUNA", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LUNA/BUSD" }, { "id": "LUNAUSDT", "asset": "LUNA", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LUNA/USDT" }, { "id": "IDEXBTC", "asset": "IDEX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "IDEX/BTC" }, { "id": "IDEXBUSD", "asset": "IDEX", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "IDEX/BUSD" }, { "id": "RSRBNB", "asset": "RSR", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "RSR/BNB" }, { "id": "RSRBTC", "asset": "RSR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RSR/BTC" }, { "id": "RSRBUSD", "asset": "RSR", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RSR/BUSD" }, { "id": "RSRUSDT", "asset": "RSR", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "RSR/USDT" }, { "id": "PAXGBNB", "asset": "PAXG", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PAXG/BNB" }, { "id": "PAXGBTC", "asset": "PAXG", "currency": "BTC", "min_size": "0.00010000", "max_size": "9222449.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00010000", "label": "PAXG/BTC" }, { "id": "PAXGBUSD", "asset": "PAXG", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "PAXG/BUSD" }, { "id": "PAXGUSDT", "asset": "PAXG", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "PAXG/USDT" }, { "id": "WNXMBNB", "asset": "WNXM", "currency": "BNB", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "WNXM/BNB" }, { "id": "WNXMBTC", "asset": "WNXM", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "WNXM/BTC" }, { "id": "WNXMBUSD", "asset": "WNXM", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WNXM/BUSD" }, { "id": "WNXMUSDT", "asset": "WNXM", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WNXM/USDT" }, { "id": "TRBBNB", "asset": "TRB", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "TRB/BNB" }, { "id": "TRBBTC", "asset": "TRB", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "TRB/BTC" }, { "id": "TRBBUSD", "asset": "TRB", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "TRB/BUSD" }, { "id": "TRBUSDT", "asset": "TRB", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "TRB/USDT" }, { "id": "ETHNGN", "asset": "ETH", "currency": "NGN", "min_size": "0.00001000", "max_size": "900.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "ETH/NGN" }, { "id": "DOTBIDR", "asset": "DOT", "currency": "BIDR", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00100000", "label": "DOT/BIDR" }, { "id": "LINKAUD", "asset": "LINK", "currency": "AUD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/AUD" }, { "id": "SXPAUD", "asset": "SXP", "currency": "AUD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SXP/AUD" }, { "id": "BZRXBNB", "asset": "BZRX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BZRX/BNB" }, { "id": "BZRXBTC", "asset": "BZRX", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BZRX/BTC" }, { "id": "BZRXBUSD", "asset": "BZRX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BZRX/BUSD" }, { "id": "BZRXUSDT", "asset": "BZRX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BZRX/USDT" }, { "id": "WBTCBTC", "asset": "WBTC", "currency": "BTC", "min_size": "0.00001000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00001000", "label": "WBTC/BTC" }, { "id": "WBTCETH", "asset": "WBTC", "currency": "ETH", "min_size": "0.00001000", "max_size": "100000.00000000", "min_total": "0.00500000", "increment": "0.00100000", "asset_increment": "0.00001000", "label": "WBTC/ETH" }, { "id": "SUSHIBNB", "asset": "SUSHI", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "SUSHI/BNB" }, { "id": "SUSHIBTC", "asset": "SUSHI", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "SUSHI/BTC" }, { "id": "SUSHIBUSD", "asset": "SUSHI", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SUSHI/BUSD" }, { "id": "SUSHIUSDT", "asset": "SUSHI", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SUSHI/USDT" }, { "id": "YFIIBNB", "asset": "YFII", "currency": "BNB", "min_size": "0.00010000", "max_size": "90000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00010000", "label": "YFII/BNB" }, { "id": "YFIIBTC", "asset": "YFII", "currency": "BTC", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00010000", "label": "YFII/BTC" }, { "id": "YFIIBUSD", "asset": "YFII", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "YFII/BUSD" }, { "id": "YFIIUSDT", "asset": "YFII", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "YFII/USDT" }, { "id": "KSMBNB", "asset": "KSM", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "KSM/BNB" }, { "id": "KSMBTC", "asset": "KSM", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "KSM/BTC" }, { "id": "KSMBUSD", "asset": "KSM", "currency": "BUSD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "KSM/BUSD" }, { "id": "KSMUSDT", "asset": "KSM", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "KSM/USDT" }, { "id": "EGLDBNB", "asset": "EGLD", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EGLD/BNB" }, { "id": "EGLDBTC", "asset": "EGLD", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "EGLD/BTC" }, { "id": "EGLDBUSD", "asset": "EGLD", "currency": "BUSD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "EGLD/BUSD" }, { "id": "EGLDUSDT", "asset": "EGLD", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "EGLD/USDT" }, { "id": "DIABNB", "asset": "DIA", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "DIA/BNB" }, { "id": "DIABTC", "asset": "DIA", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "DIA/BTC" }, { "id": "DIABUSD", "asset": "DIA", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DIA/BUSD" }, { "id": "DIAUSDT", "asset": "DIA", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DIA/USDT" }, { "id": "RUNEUSDT", "asset": "RUNE", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "RUNE/USDT" }, { "id": "FIOUSDT", "asset": "FIO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FIO/USDT" }, { "id": "UMABTC", "asset": "UMA", "currency": "BTC", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.00100000", "label": "UMA/BTC" }, { "id": "UMAUSDT", "asset": "UMA", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UMA/USDT" }, { "id": "EOSUPUSDT", "asset": "EOSUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "EOSUP/USDT" }, { "id": "EOSDOWNUSDT", "asset": "EOSDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "EOSDOWN/USDT" }, { "id": "TRXUPUSDT", "asset": "TRXUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "TRXUP/USDT" }, { "id": "TRXDOWNUSDT", "asset": "TRXDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "TRXDOWN/USDT" }, { "id": "XRPUPUSDT", "asset": "XRPUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XRPUP/USDT" }, { "id": "XRPDOWNUSDT", "asset": "XRPDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "99999999.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "XRPDOWN/USDT" }, { "id": "DOTUPUSDT", "asset": "DOTUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "DOTUP/USDT" }, { "id": "DOTDOWNUSDT", "asset": "DOTDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DOTDOWN/USDT" }, { "id": "SRMBIDR", "asset": "SRM", "currency": "BIDR", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00100000", "label": "SRM/BIDR" }, { "id": "ONEBIDR", "asset": "ONE", "currency": "BIDR", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "20000.00", "increment": "0.01", "asset_increment": "1.00000000", "label": "ONE/BIDR" }, { "id": "LINKTRY", "asset": "LINK", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.10000000", "asset_increment": "0.01000000", "label": "LINK/TRY" }, { "id": "USDTNGN", "asset": "USDT", "currency": "NGN", "min_size": "0.01000000", "max_size": "922320.00000000", "min_total": "500.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "USDT/NGN" }, { "id": "BELBNB", "asset": "BEL", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BEL/BNB" }, { "id": "BELBTC", "asset": "BEL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "BEL/BTC" }, { "id": "BELBUSD", "asset": "BEL", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BEL/BUSD" }, { "id": "BELUSDT", "asset": "BEL", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BEL/USDT" }, { "id": "WINGBNB", "asset": "WING", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "WING/BNB" }, { "id": "WINGBTC", "asset": "WING", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "WING/BTC" }, { "id": "SWRVBNB", "asset": "SWRV", "currency": "BNB", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "SWRV/BNB" }, { "id": "SWRVBUSD", "asset": "SWRV", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SWRV/BUSD" }, { "id": "WINGBUSD", "asset": "WING", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WING/BUSD" }, { "id": "WINGUSDT", "asset": "WING", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "WING/USDT" }, { "id": "LTCUPUSDT", "asset": "LTCUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "LTCUP/USDT" }, { "id": "LTCDOWNUSDT", "asset": "LTCDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LTCDOWN/USDT" }, { "id": "LENDBKRW", "asset": "LEND", "currency": "BKRW", "min_size": "0.10000000", "max_size": "92232.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "LEND/BKRW" }, { "id": "SXPEUR", "asset": "SXP", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SXP/EUR" }, { "id": "CREAMBNB", "asset": "CREAM", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CREAM/BNB" }, { "id": "CREAMBUSD", "asset": "CREAM", "currency": "BUSD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "CREAM/BUSD" }, { "id": "UNIBNB", "asset": "UNI", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "UNI/BNB" }, { "id": "UNIBTC", "asset": "UNI", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "UNI/BTC" }, { "id": "UNIBUSD", "asset": "UNI", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UNI/BUSD" }, { "id": "UNIUSDT", "asset": "UNI", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UNI/USDT" }, { "id": "NBSBTC", "asset": "NBS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "NBS/BTC" }, { "id": "NBSUSDT", "asset": "NBS", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NBS/USDT" }, { "id": "OXTBTC", "asset": "OXT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OXT/BTC" }, { "id": "OXTUSDT", "asset": "OXT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OXT/USDT" }, { "id": "SUNBTC", "asset": "SUN", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "SUN/BTC" }, { "id": "SUNUSDT", "asset": "SUN", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SUN/USDT" }, { "id": "AVAXBNB", "asset": "AVAX", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AVAX/BNB" }, { "id": "AVAXBTC", "asset": "AVAX", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "AVAX/BTC" }, { "id": "AVAXBUSD", "asset": "AVAX", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "AVAX/BUSD" }, { "id": "AVAXUSDT", "asset": "AVAX", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "AVAX/USDT" }, { "id": "HNTBTC", "asset": "HNT", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "HNT/BTC" }, { "id": "HNTUSDT", "asset": "HNT", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "HNT/USDT" }, { "id": "BAKEBNB", "asset": "BAKE", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BAKE/BNB" }, { "id": "BURGERBNB", "asset": "BURGER", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BURGER/BNB" }, { "id": "SXPBIDR", "asset": "SXP", "currency": "BIDR", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "SXP/BIDR" }, { "id": "LINKBKRW", "asset": "LINK", "currency": "BKRW", "min_size": "0.10000000", "max_size": "9200.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "LINK/BKRW" }, { "id": "FLMBNB", "asset": "FLM", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FLM/BNB" }, { "id": "FLMBTC", "asset": "FLM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FLM/BTC" }, { "id": "FLMBUSD", "asset": "FLM", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FLM/BUSD" }, { "id": "FLMUSDT", "asset": "FLM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FLM/USDT" }, { "id": "SCRTBTC", "asset": "SCRT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SCRT/BTC" }, { "id": "SCRTETH", "asset": "SCRT", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "SCRT/ETH" }, { "id": "CAKEBNB", "asset": "CAKE", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "CAKE/BNB" }, { "id": "CAKEBUSD", "asset": "CAKE", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CAKE/BUSD" }, { "id": "SPARTABNB", "asset": "SPARTA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "SPARTA/BNB" }, { "id": "UNIUPUSDT", "asset": "UNIUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "UNIUP/USDT" }, { "id": "UNIDOWNUSDT", "asset": "UNIDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "99999999.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "UNIDOWN/USDT" }, { "id": "ORNBTC", "asset": "ORN", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ORN/BTC" }, { "id": "ORNUSDT", "asset": "ORN", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ORN/USDT" }, { "id": "TRXNGN", "asset": "TRX", "currency": "NGN", "min_size": "0.01000000", "max_size": "922320.00000000", "min_total": "500.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "TRX/NGN" }, { "id": "SXPTRY", "asset": "SXP", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "SXP/TRY" }, { "id": "UTKBTC", "asset": "UTK", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "UTK/BTC" }, { "id": "UTKUSDT", "asset": "UTK", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "UTK/USDT" }, { "id": "XVSBNB", "asset": "XVS", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XVS/BNB" }, { "id": "XVSBTC", "asset": "XVS", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "XVS/BTC" }, { "id": "XVSBUSD", "asset": "XVS", "currency": "BUSD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "XVS/BUSD" }, { "id": "XVSUSDT", "asset": "XVS", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "XVS/USDT" }, { "id": "ALPHABNB", "asset": "ALPHA", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ALPHA/BNB" }, { "id": "ALPHABTC", "asset": "ALPHA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ALPHA/BTC" }, { "id": "ALPHABUSD", "asset": "ALPHA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALPHA/BUSD" }, { "id": "ALPHAUSDT", "asset": "ALPHA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALPHA/USDT" }, { "id": "VIDTBTC", "asset": "VIDT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VIDT/BTC" }, { "id": "VIDTBUSD", "asset": "VIDT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "VIDT/BUSD" }, { "id": "AAVEBNB", "asset": "AAVE", "currency": "BNB", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AAVE/BNB" }, { "id": "BTCBRL", "asset": "BTC", "currency": "BRL", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "BTC/BRL" }, { "id": "USDTBRL", "asset": "USDT", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "USDT/BRL" }, { "id": "AAVEBTC", "asset": "AAVE", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "AAVE/BTC" }, { "id": "AAVEETH", "asset": "AAVE", "currency": "ETH", "min_size": "0.00100000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00001000", "asset_increment": "0.00100000", "label": "AAVE/ETH" }, { "id": "AAVEBUSD", "asset": "AAVE", "currency": "BUSD", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "AAVE/BUSD" }, { "id": "AAVEUSDT", "asset": "AAVE", "currency": "USDT", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "AAVE/USDT" }, { "id": "AAVEBKRW", "asset": "AAVE", "currency": "BKRW", "min_size": "0.00100000", "max_size": "9000.00000000", "min_total": "1000.00000000", "increment": "1.00000000", "asset_increment": "0.00100000", "label": "AAVE/BKRW" }, { "id": "NEARBNB", "asset": "NEAR", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "NEAR/BNB" }, { "id": "NEARBTC", "asset": "NEAR", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "NEAR/BTC" }, { "id": "NEARBUSD", "asset": "NEAR", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NEAR/BUSD" }, { "id": "NEARUSDT", "asset": "NEAR", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "NEAR/USDT" }, { "id": "SXPUPUSDT", "asset": "SXPUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SXPUP/USDT" }, { "id": "SXPDOWNUSDT", "asset": "SXPDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "SXPDOWN/USDT" }, { "id": "DOTBKRW", "asset": "DOT", "currency": "BKRW", "min_size": "0.10000000", "max_size": "9200.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "DOT/BKRW" }, { "id": "SXPGBP", "asset": "SXP", "currency": "GBP", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SXP/GBP" }, { "id": "FILBNB", "asset": "FIL", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FIL/BNB" }, { "id": "FILBTC", "asset": "FIL", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "FIL/BTC" }, { "id": "FILBUSD", "asset": "FIL", "currency": "BUSD", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "FIL/BUSD" }, { "id": "FILUSDT", "asset": "FIL", "currency": "USDT", "min_size": "0.00010000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "FIL/USDT" }, { "id": "FILUPUSDT", "asset": "FILUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "FILUP/USDT" }, { "id": "FILDOWNUSDT", "asset": "FILDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "FILDOWN/USDT" }, { "id": "YFIUPUSDT", "asset": "YFIUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "YFIUP/USDT" }, { "id": "YFIDOWNUSDT", "asset": "YFIDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "99999999.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "YFIDOWN/USDT" }, { "id": "INJBNB", "asset": "INJ", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "INJ/BNB" }, { "id": "INJBTC", "asset": "INJ", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "INJ/BTC" }, { "id": "INJBUSD", "asset": "INJ", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "INJ/BUSD" }, { "id": "INJUSDT", "asset": "INJ", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "INJ/USDT" }, { "id": "AERGOBTC", "asset": "AERGO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AERGO/BTC" }, { "id": "AERGOBUSD", "asset": "AERGO", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "AERGO/BUSD" }, { "id": "LINKEUR", "asset": "LINK", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/EUR" }, { "id": "ONEBUSD", "asset": "ONE", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/BUSD" }, { "id": "EASYETH", "asset": "EASY", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "EASY/ETH" }, { "id": "AUDIOBTC", "asset": "AUDIO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AUDIO/BTC" }, { "id": "AUDIOBUSD", "asset": "AUDIO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AUDIO/BUSD" }, { "id": "AUDIOUSDT", "asset": "AUDIO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AUDIO/USDT" }, { "id": "CTKBNB", "asset": "CTK", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "CTK/BNB" }, { "id": "CTKBTC", "asset": "CTK", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "CTK/BTC" }, { "id": "CTKBUSD", "asset": "CTK", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CTK/BUSD" }, { "id": "CTKUSDT", "asset": "CTK", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CTK/USDT" }, { "id": "BCHUPUSDT", "asset": "BCHUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BCHUP/USDT" }, { "id": "BCHDOWNUSDT", "asset": "BCHDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BCHDOWN/USDT" }, { "id": "BOTBTC", "asset": "BOT", "currency": "BTC", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00010000", "label": "BOT/BTC" }, { "id": "BOTBUSD", "asset": "BOT", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BOT/BUSD" }, { "id": "ETHBRL", "asset": "ETH", "currency": "BRL", "min_size": "0.00001000", "max_size": "45000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/BRL" }, { "id": "DOTEUR", "asset": "DOT", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DOT/EUR" }, { "id": "AKROBTC", "asset": "AKRO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AKRO/BTC" }, { "id": "AKROUSDT", "asset": "AKRO", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "AKRO/USDT" }, { "id": "KP3RBNB", "asset": "KP3R", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.00100000", "label": "KP3R/BNB" }, { "id": "KP3RBUSD", "asset": "KP3R", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "KP3R/BUSD" }, { "id": "AXSBNB", "asset": "AXS", "currency": "BNB", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "AXS/BNB" }, { "id": "AXSBTC", "asset": "AXS", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AXS/BTC" }, { "id": "AXSBUSD", "asset": "AXS", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AXS/BUSD" }, { "id": "AXSUSDT", "asset": "AXS", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AXS/USDT" }, { "id": "HARDBNB", "asset": "HARD", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.10000000", "label": "HARD/BNB" }, { "id": "HARDBTC", "asset": "HARD", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "HARD/BTC" }, { "id": "HARDBUSD", "asset": "HARD", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "HARD/BUSD" }, { "id": "HARDUSDT", "asset": "HARD", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "HARD/USDT" }, { "id": "BNBBRL", "asset": "BNB", "currency": "BRL", "min_size": "0.00001000", "max_size": "45000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BNB/BRL" }, { "id": "LTCEUR", "asset": "LTC", "currency": "EUR", "min_size": "0.00010000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00010000", "label": "LTC/EUR" }, { "id": "RENBTCBTC", "asset": "RENBTC", "currency": "BTC", "min_size": "0.00001000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00001000", "label": "RENBTC/BTC" }, { "id": "RENBTCETH", "asset": "RENBTC", "currency": "ETH", "min_size": "0.00001000", "max_size": "100000.00000000", "min_total": "0.00500000", "increment": "0.00100000", "asset_increment": "0.00001000", "label": "RENBTC/ETH" }, { "id": "DNTBUSD", "asset": "DNT", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DNT/BUSD" }, { "id": "DNTUSDT", "asset": "DNT", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DNT/USDT" }, { "id": "SLPETH", "asset": "SLP", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SLP/ETH" }, { "id": "ADAEUR", "asset": "ADA", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/EUR" }, { "id": "LTCNGN", "asset": "LTC", "currency": "NGN", "min_size": "0.00001000", "max_size": "9221.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "LTC/NGN" }, { "id": "CVPETH", "asset": "CVP", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "CVP/ETH" }, { "id": "CVPBUSD", "asset": "CVP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CVP/BUSD" }, { "id": "STRAXBTC", "asset": "STRAX", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "STRAX/BTC" }, { "id": "STRAXETH", "asset": "STRAX", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "STRAX/ETH" }, { "id": "STRAXBUSD", "asset": "STRAX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STRAX/BUSD" }, { "id": "STRAXUSDT", "asset": "STRAX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STRAX/USDT" }, { "id": "FORBTC", "asset": "FOR", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "FOR/BTC" }, { "id": "FORBUSD", "asset": "FOR", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "FOR/BUSD" }, { "id": "UNFIBNB", "asset": "UNFI", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "UNFI/BNB" }, { "id": "UNFIBTC", "asset": "UNFI", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "UNFI/BTC" }, { "id": "UNFIBUSD", "asset": "UNFI", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UNFI/BUSD" }, { "id": "UNFIUSDT", "asset": "UNFI", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UNFI/USDT" }, { "id": "FRONTETH", "asset": "FRONT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "FRONT/ETH" }, { "id": "FRONTBUSD", "asset": "FRONT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "FRONT/BUSD" }, { "id": "BCHABUSD", "asset": "BCHA", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BCHA/BUSD" }, { "id": "ROSEBTC", "asset": "ROSE", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ROSE/BTC" }, { "id": "ROSEBUSD", "asset": "ROSE", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ROSE/BUSD" }, { "id": "ROSEUSDT", "asset": "ROSE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ROSE/USDT" }, { "id": "AVAXTRY", "asset": "AVAX", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.10000000", "asset_increment": "0.01000000", "label": "AVAX/TRY" }, { "id": "BUSDBRL", "asset": "BUSD", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "BUSD/BRL" }, { "id": "AVAUSDT", "asset": "AVA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AVA/USDT" }, { "id": "SYSBUSD", "asset": "SYS", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SYS/BUSD" }, { "id": "XEMUSDT", "asset": "XEM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XEM/USDT" }, { "id": "HEGICETH", "asset": "HEGIC", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "HEGIC/ETH" }, { "id": "HEGICBUSD", "asset": "HEGIC", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "HEGIC/BUSD" }, { "id": "AAVEUPUSDT", "asset": "AAVEUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "AAVEUP/USDT" }, { "id": "AAVEDOWNUSDT", "asset": "AAVEDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "AAVEDOWN/USDT" }, { "id": "PROMBNB", "asset": "PROM", "currency": "BNB", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "PROM/BNB" }, { "id": "PROMBUSD", "asset": "PROM", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PROM/BUSD" }, { "id": "XRPBRL", "asset": "XRP", "currency": "BRL", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XRP/BRL" }, { "id": "XRPNGN", "asset": "XRP", "currency": "NGN", "min_size": "0.01000000", "max_size": "922320.00000000", "min_total": "500.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "XRP/NGN" }, { "id": "SKLBTC", "asset": "SKL", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SKL/BTC" }, { "id": "SKLBUSD", "asset": "SKL", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SKL/BUSD" }, { "id": "SKLUSDT", "asset": "SKL", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "SKL/USDT" }, { "id": "BCHEUR", "asset": "BCH", "currency": "EUR", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/EUR" }, { "id": "YFIEUR", "asset": "YFI", "currency": "EUR", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "YFI/EUR" }, { "id": "ZILBIDR", "asset": "ZIL", "currency": "BIDR", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "20000.00", "increment": "0.01", "asset_increment": "1.00000000", "label": "ZIL/BIDR" }, { "id": "SUSDBTC", "asset": "SUSD", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SUSD/BTC" }, { "id": "SUSDETH", "asset": "SUSD", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "SUSD/ETH" }, { "id": "SUSDUSDT", "asset": "SUSD", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SUSD/USDT" }, { "id": "COVERETH", "asset": "COVER", "currency": "ETH", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00010000", "asset_increment": "0.00010000", "label": "COVER/ETH" }, { "id": "COVERBUSD", "asset": "COVER", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "COVER/BUSD" }, { "id": "GLMBTC", "asset": "GLM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GLM/BTC" }, { "id": "GLMETH", "asset": "GLM", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "GLM/ETH" }, { "id": "GHSTETH", "asset": "GHST", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "GHST/ETH" }, { "id": "GHSTBUSD", "asset": "GHST", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GHST/BUSD" }, { "id": "SUSHIUPUSDT", "asset": "SUSHIUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "SUSHIUP/USDT" }, { "id": "SUSHIDOWNUSDT", "asset": "SUSHIDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "99999999.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "SUSHIDOWN/USDT" }, { "id": "XLMUPUSDT", "asset": "XLMUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "920000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XLMUP/USDT" }, { "id": "XLMDOWNUSDT", "asset": "XLMDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "XLMDOWN/USDT" }, { "id": "LINKBRL", "asset": "LINK", "currency": "BRL", "min_size": "0.00001000", "max_size": "45000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LINK/BRL" }, { "id": "LINKNGN", "asset": "LINK", "currency": "NGN", "min_size": "0.00001000", "max_size": "92232.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "LINK/NGN" }, { "id": "LTCRUB", "asset": "LTC", "currency": "RUB", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "100.00000000", "increment": "0.10000000", "asset_increment": "0.00001000", "label": "LTC/RUB" }, { "id": "TRXTRY", "asset": "TRX", "currency": "TRY", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "TRX/TRY" }, { "id": "XLMEUR", "asset": "XLM", "currency": "EUR", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/EUR" }, { "id": "DFETH", "asset": "DF", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DF/ETH" }, { "id": "DFBUSD", "asset": "DF", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DF/BUSD" }, { "id": "GRTBTC", "asset": "GRT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GRT/BTC" }, { "id": "GRTETH", "asset": "GRT", "currency": "ETH", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "GRT/ETH" }, { "id": "GRTUSDT", "asset": "GRT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GRT/USDT" }, { "id": "JUVBTC", "asset": "JUV", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "JUV/BTC" }, { "id": "JUVBUSD", "asset": "JUV", "currency": "BUSD", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "JUV/BUSD" }, { "id": "JUVUSDT", "asset": "JUV", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "JUV/USDT" }, { "id": "PSGBTC", "asset": "PSG", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "PSG/BTC" }, { "id": "PSGBUSD", "asset": "PSG", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PSG/BUSD" }, { "id": "PSGUSDT", "asset": "PSG", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PSG/USDT" }, { "id": "BUSDBVND", "asset": "BUSD", "currency": "BVND", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "30000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "BUSD/BVND" }, { "id": "USDTBVND", "asset": "USDT", "currency": "BVND", "min_size": "0.01000000", "max_size": "1000000.00000000", "min_total": "30000.00", "increment": "1.00", "asset_increment": "0.01000000", "label": "USDT/BVND" }, { "id": "1INCHBTC", "asset": "1INCH", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "1INCH/BTC" }, { "id": "1INCHUSDT", "asset": "1INCH", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "1INCH/USDT" }, { "id": "REEFBTC", "asset": "REEF", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "REEF/BTC" }, { "id": "REEFUSDT", "asset": "REEF", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "REEF/USDT" }, { "id": "OGBTC", "asset": "OG", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "OG/BTC" }, { "id": "OGUSDT", "asset": "OG", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "OG/USDT" }, { "id": "ATMBTC", "asset": "ATM", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ATM/BTC" }, { "id": "ATMUSDT", "asset": "ATM", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATM/USDT" }, { "id": "ASRBTC", "asset": "ASR", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ASR/BTC" }, { "id": "ASRUSDT", "asset": "ASR", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ASR/USDT" }, { "id": "CELOBTC", "asset": "CELO", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "CELO/BTC" }, { "id": "CELOUSDT", "asset": "CELO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CELO/USDT" }, { "id": "RIFBTC", "asset": "RIF", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RIF/BTC" }, { "id": "RIFUSDT", "asset": "RIF", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "RIF/USDT" }, { "id": "CHZTRY", "asset": "CHZ", "currency": "TRY", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "CHZ/TRY" }, { "id": "XLMTRY", "asset": "XLM", "currency": "TRY", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "XLM/TRY" }, { "id": "LINKGBP", "asset": "LINK", "currency": "GBP", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LINK/GBP" }, { "id": "GRTEUR", "asset": "GRT", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GRT/EUR" }, { "id": "BTCSTBTC", "asset": "BTCST", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "BTCST/BTC" }, { "id": "BTCSTBUSD", "asset": "BTCST", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BTCST/BUSD" }, { "id": "BTCSTUSDT", "asset": "BTCST", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BTCST/USDT" }, { "id": "TRUBTC", "asset": "TRU", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "TRU/BTC" }, { "id": "TRUBUSD", "asset": "TRU", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TRU/BUSD" }, { "id": "TRUUSDT", "asset": "TRU", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TRU/USDT" }, { "id": "DEXEETH", "asset": "DEXE", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "DEXE/ETH" }, { "id": "DEXEBUSD", "asset": "DEXE", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DEXE/BUSD" }, { "id": "EOSEUR", "asset": "EOS", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "EOS/EUR" }, { "id": "LTCBRL", "asset": "LTC", "currency": "BRL", "min_size": "0.00001000", "max_size": "45000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/BRL" }, { "id": "USDCBUSD", "asset": "USDC", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "USDC/BUSD" }, { "id": "TUSDBUSD", "asset": "TUSD", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TUSD/BUSD" }, { "id": "PAXBUSD", "asset": "PAX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "PAX/BUSD" }, { "id": "CKBBTC", "asset": "CKB", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "CKB/BTC" }, { "id": "CKBBUSD", "asset": "CKB", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CKB/BUSD" }, { "id": "CKBUSDT", "asset": "CKB", "currency": "USDT", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "CKB/USDT" }, { "id": "TWTBTC", "asset": "TWT", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TWT/BTC" }, { "id": "TWTBUSD", "asset": "TWT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TWT/BUSD" }, { "id": "TWTUSDT", "asset": "TWT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TWT/USDT" }, { "id": "FIROBTC", "asset": "FIRO", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "FIRO/BTC" }, { "id": "FIROETH", "asset": "FIRO", "currency": "ETH", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "FIRO/ETH" }, { "id": "FIROUSDT", "asset": "FIRO", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FIRO/USDT" }, { "id": "BETHETH", "asset": "BETH", "currency": "ETH", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "0.00500000", "increment": "0.00010000", "asset_increment": "0.00010000", "label": "BETH/ETH" }, { "id": "DOGEEUR", "asset": "DOGE", "currency": "EUR", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOGE/EUR" }, { "id": "DOGETRY", "asset": "DOGE", "currency": "TRY", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "DOGE/TRY" }, { "id": "DOGEAUD", "asset": "DOGE", "currency": "AUD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOGE/AUD" }, { "id": "DOGEBRL", "asset": "DOGE", "currency": "BRL", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "DOGE/BRL" }, { "id": "DOTNGN", "asset": "DOT", "currency": "NGN", "min_size": "0.00001000", "max_size": "92232.00000000", "min_total": "500.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "DOT/NGN" }, { "id": "PROSETH", "asset": "PROS", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "PROS/ETH" }, { "id": "LITBTC", "asset": "LIT", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "LIT/BTC" }, { "id": "LITBUSD", "asset": "LIT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LIT/BUSD" }, { "id": "LITUSDT", "asset": "LIT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LIT/USDT" }, { "id": "BTCVAI", "asset": "BTC", "currency": "VAI", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/VAI" }, { "id": "BUSDVAI", "asset": "BUSD", "currency": "VAI", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BUSD/VAI" }, { "id": "SFPBTC", "asset": "SFP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "SFP/BTC" }, { "id": "SFPBUSD", "asset": "SFP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SFP/BUSD" }, { "id": "SFPUSDT", "asset": "SFP", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SFP/USDT" }, { "id": "DOGEGBP", "asset": "DOGE", "currency": "GBP", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "DOGE/GBP" }, { "id": "DOTTRY", "asset": "DOT", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.10000000", "asset_increment": "0.01000000", "label": "DOT/TRY" }, { "id": "FXSBTC", "asset": "FXS", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "FXS/BTC" }, { "id": "FXSBUSD", "asset": "FXS", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FXS/BUSD" }, { "id": "DODOBTC", "asset": "DODO", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "DODO/BTC" }, { "id": "DODOBUSD", "asset": "DODO", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DODO/BUSD" }, { "id": "DODOUSDT", "asset": "DODO", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DODO/USDT" }, { "id": "FRONTBTC", "asset": "FRONT", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "FRONT/BTC" }, { "id": "EASYBTC", "asset": "EASY", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "EASY/BTC" }, { "id": "CAKEBTC", "asset": "CAKE", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "CAKE/BTC" }, { "id": "CAKEUSDT", "asset": "CAKE", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CAKE/USDT" }, { "id": "BAKEBUSD", "asset": "BAKE", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAKE/BUSD" }, { "id": "UFTETH", "asset": "UFT", "currency": "ETH", "min_size": "0.01000000", "max_size": "9000000.00000000", "min_total": "0.00500000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "UFT/ETH" }, { "id": "UFTBUSD", "asset": "UFT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "UFT/BUSD" }, { "id": "1INCHBUSD", "asset": "1INCH", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "1INCH/BUSD" }, { "id": "BANDBUSD", "asset": "BAND", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAND/BUSD" }, { "id": "GRTBUSD", "asset": "GRT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "GRT/BUSD" }, { "id": "IOSTBUSD", "asset": "IOST", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "IOST/BUSD" }, { "id": "OMGBUSD", "asset": "OMG", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OMG/BUSD" }, { "id": "REEFBUSD", "asset": "REEF", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "REEF/BUSD" }, { "id": "ACMBTC", "asset": "ACM", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "ACM/BTC" }, { "id": "ACMBUSD", "asset": "ACM", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ACM/BUSD" }, { "id": "ACMUSDT", "asset": "ACM", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ACM/USDT" }, { "id": "AUCTIONBTC", "asset": "AUCTION", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "AUCTION/BTC" }, { "id": "AUCTIONBUSD", "asset": "AUCTION", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "AUCTION/BUSD" }, { "id": "PHABTC", "asset": "PHA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "PHA/BTC" }, { "id": "PHABUSD", "asset": "PHA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "PHA/BUSD" }, { "id": "DOTGBP", "asset": "DOT", "currency": "GBP", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DOT/GBP" }, { "id": "ADATRY", "asset": "ADA", "currency": "TRY", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "ADA/TRY" }, { "id": "ADABRL", "asset": "ADA", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "ADA/BRL" }, { "id": "ADAGBP", "asset": "ADA", "currency": "GBP", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ADA/GBP" }, { "id": "TVKBTC", "asset": "TVK", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TVK/BTC" }, { "id": "TVKBUSD", "asset": "TVK", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TVK/BUSD" }, { "id": "BADGERBTC", "asset": "BADGER", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "BADGER/BTC" }, { "id": "BADGERBUSD", "asset": "BADGER", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BADGER/BUSD" }, { "id": "BADGERUSDT", "asset": "BADGER", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BADGER/USDT" }, { "id": "FISBTC", "asset": "FIS", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "FIS/BTC" }, { "id": "FISBUSD", "asset": "FIS", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FIS/BUSD" }, { "id": "FISUSDT", "asset": "FIS", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FIS/USDT" }, { "id": "DOTBRL", "asset": "DOT", "currency": "BRL", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "DOT/BRL" }, { "id": "ADAAUD", "asset": "ADA", "currency": "AUD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ADA/AUD" }, { "id": "HOTTRY", "asset": "HOT", "currency": "TRY", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "HOT/TRY" }, { "id": "EGLDEUR", "asset": "EGLD", "currency": "EUR", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "EGLD/EUR" }, { "id": "OMBTC", "asset": "OM", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "OM/BTC" }, { "id": "OMBUSD", "asset": "OM", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OM/BUSD" }, { "id": "OMUSDT", "asset": "OM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OM/USDT" }, { "id": "PONDBTC", "asset": "POND", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "POND/BTC" }, { "id": "PONDBUSD", "asset": "POND", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "POND/BUSD" }, { "id": "PONDUSDT", "asset": "POND", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "POND/USDT" }, { "id": "DEGOBTC", "asset": "DEGO", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "DEGO/BTC" }, { "id": "DEGOBUSD", "asset": "DEGO", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DEGO/BUSD" }, { "id": "DEGOUSDT", "asset": "DEGO", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "DEGO/USDT" }, { "id": "AVAXEUR", "asset": "AVAX", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "AVAX/EUR" }, { "id": "BTTTRY", "asset": "BTT", "currency": "TRY", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "BTT/TRY" }, { "id": "CHZBRL", "asset": "CHZ", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "CHZ/BRL" }, { "id": "UNIEUR", "asset": "UNI", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "UNI/EUR" }, { "id": "ALICEBTC", "asset": "ALICE", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "ALICE/BTC" }, { "id": "ALICEBUSD", "asset": "ALICE", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALICE/BUSD" }, { "id": "ALICEUSDT", "asset": "ALICE", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALICE/USDT" }, { "id": "CHZBUSD", "asset": "CHZ", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CHZ/BUSD" }, { "id": "CHZEUR", "asset": "CHZ", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CHZ/EUR" }, { "id": "CHZGBP", "asset": "CHZ", "currency": "GBP", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "CHZ/GBP" }, { "id": "BIFIBNB", "asset": "BIFI", "currency": "BNB", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "0.05000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BIFI/BNB" }, { "id": "BIFIBUSD", "asset": "BIFI", "currency": "BUSD", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BIFI/BUSD" }, { "id": "LINABTC", "asset": "LINA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "LINA/BTC" }, { "id": "LINABUSD", "asset": "LINA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LINA/BUSD" }, { "id": "LINAUSDT", "asset": "LINA", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "LINA/USDT" }, { "id": "ADARUB", "asset": "ADA", "currency": "RUB", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ADA/RUB" }, { "id": "ENJBRL", "asset": "ENJ", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "ENJ/BRL" }, { "id": "ENJEUR", "asset": "ENJ", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ENJ/EUR" }, { "id": "MATICEUR", "asset": "MATIC", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MATIC/EUR" }, { "id": "NEOTRY", "asset": "NEO", "currency": "TRY", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.10000000", "asset_increment": "0.01000000", "label": "NEO/TRY" }, { "id": "PERPBTC", "asset": "PERP", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "PERP/BTC" }, { "id": "PERPBUSD", "asset": "PERP", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PERP/BUSD" }, { "id": "PERPUSDT", "asset": "PERP", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PERP/USDT" }, { "id": "RAMPBTC", "asset": "RAMP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "RAMP/BTC" }, { "id": "RAMPBUSD", "asset": "RAMP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "RAMP/BUSD" }, { "id": "RAMPUSDT", "asset": "RAMP", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "RAMP/USDT" }, { "id": "SUPERBTC", "asset": "SUPER", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "SUPER/BTC" }, { "id": "SUPERBUSD", "asset": "SUPER", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SUPER/BUSD" }, { "id": "SUPERUSDT", "asset": "SUPER", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "SUPER/USDT" }, { "id": "CFXBTC", "asset": "CFX", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "CFX/BTC" }, { "id": "CFXBUSD", "asset": "CFX", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CFX/BUSD" }, { "id": "CFXUSDT", "asset": "CFX", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CFX/USDT" }, { "id": "ENJGBP", "asset": "ENJ", "currency": "GBP", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ENJ/GBP" }, { "id": "EOSTRY", "asset": "EOS", "currency": "TRY", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "EOS/TRY" }, { "id": "LTCGBP", "asset": "LTC", "currency": "GBP", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/GBP" }, { "id": "LUNAEUR", "asset": "LUNA", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "LUNA/EUR" }, { "id": "RVNTRY", "asset": "RVN", "currency": "TRY", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "RVN/TRY" }, { "id": "THETAEUR", "asset": "THETA", "currency": "EUR", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "THETA/EUR" }, { "id": "XVGBUSD", "asset": "XVG", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XVG/BUSD" }, { "id": "EPSBTC", "asset": "EPS", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "EPS/BTC" }, { "id": "EPSBUSD", "asset": "EPS", "currency": "BUSD", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "EPS/BUSD" }, { "id": "EPSUSDT", "asset": "EPS", "currency": "USDT", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "EPS/USDT" }, { "id": "AUTOBTC", "asset": "AUTO", "currency": "BTC", "min_size": "0.00010000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00001000", "asset_increment": "0.00010000", "label": "AUTO/BTC" }, { "id": "AUTOBUSD", "asset": "AUTO", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "AUTO/BUSD" }, { "id": "AUTOUSDT", "asset": "AUTO", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "AUTO/USDT" }, { "id": "TKOBTC", "asset": "TKO", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "TKO/BTC" }, { "id": "TKOBIDR", "asset": "TKO", "currency": "BIDR", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "20000.00", "increment": "0.01", "asset_increment": "1.00000000", "label": "TKO/BIDR" }, { "id": "TKOBUSD", "asset": "TKO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TKO/BUSD" }, { "id": "TKOUSDT", "asset": "TKO", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TKO/USDT" }, { "id": "PUNDIXETH", "asset": "PUNDIX", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "PUNDIX/ETH" }, { "id": "PUNDIXUSDT", "asset": "PUNDIX", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "PUNDIX/USDT" }, { "id": "BTTBRL", "asset": "BTT", "currency": "BRL", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "BTT/BRL" }, { "id": "BTTEUR", "asset": "BTT", "currency": "EUR", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "BTT/EUR" }, { "id": "HOTEUR", "asset": "HOT", "currency": "EUR", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HOT/EUR" }, { "id": "WINEUR", "asset": "WIN", "currency": "EUR", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "WIN/EUR" }, { "id": "TLMBTC", "asset": "TLM", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "TLM/BTC" }, { "id": "TLMBUSD", "asset": "TLM", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TLM/BUSD" }, { "id": "TLMUSDT", "asset": "TLM", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TLM/USDT" }, { "id": "1INCHUPUSDT", "asset": "1INCHUP", "currency": "USDT", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "1INCHUP/USDT" }, { "id": "1INCHDOWNUSDT", "asset": "1INCHDOWN", "currency": "USDT", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "1INCHDOWN/USDT" }, { "id": "BTGBUSD", "asset": "BTG", "currency": "BUSD", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BTG/BUSD" }, { "id": "BTGUSDT", "asset": "BTG", "currency": "USDT", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BTG/USDT" }, { "id": "HOTBUSD", "asset": "HOT", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HOT/BUSD" }, { "id": "BNBUAH", "asset": "BNB", "currency": "UAH", "min_size": "0.00001000", "max_size": "90000.00000000", "min_total": "100.00000000", "increment": "0.10000000", "asset_increment": "0.00001000", "label": "BNB/UAH" }, { "id": "ONTTRY", "asset": "ONT", "currency": "TRY", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ONT/TRY" }, { "id": "VETEUR", "asset": "VET", "currency": "EUR", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "VET/EUR" }, { "id": "VETGBP", "asset": "VET", "currency": "GBP", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "VET/GBP" }, { "id": "WINBRL", "asset": "WIN", "currency": "BRL", "min_size": "1.00000000", "max_size": "92000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "WIN/BRL" }, { "id": "MIRBTC", "asset": "MIR", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "MIR/BTC" }, { "id": "MIRBUSD", "asset": "MIR", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "MIR/BUSD" }, { "id": "MIRUSDT", "asset": "MIR", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "MIR/USDT" }, { "id": "BARBTC", "asset": "BAR", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "BAR/BTC" }, { "id": "BARBUSD", "asset": "BAR", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAR/BUSD" }, { "id": "BARUSDT", "asset": "BAR", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "BAR/USDT" }, { "id": "FORTHBTC", "asset": "FORTH", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "FORTH/BTC" }, { "id": "FORTHBUSD", "asset": "FORTH", "currency": "BUSD", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FORTH/BUSD" }, { "id": "FORTHUSDT", "asset": "FORTH", "currency": "USDT", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "FORTH/USDT" }, { "id": "CAKEGBP", "asset": "CAKE", "currency": "GBP", "min_size": "0.00100000", "max_size": "90000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "CAKE/GBP" }, { "id": "DOGERUB", "asset": "DOGE", "currency": "RUB", "min_size": "0.10000000", "max_size": "100000.00000000", "min_total": "100.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "DOGE/RUB" }, { "id": "HOTBRL", "asset": "HOT", "currency": "BRL", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "HOT/BRL" }, { "id": "WRXEUR", "asset": "WRX", "currency": "EUR", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "WRX/EUR" }, { "id": "EZBTC", "asset": "EZ", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "EZ/BTC" }, { "id": "EZETH", "asset": "EZ", "currency": "ETH", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00500000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "EZ/ETH" }, { "id": "BAKEUSDT", "asset": "BAKE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.10000000", "label": "BAKE/USDT" }, { "id": "BURGERBUSD", "asset": "BURGER", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "BURGER/BUSD" }, { "id": "BURGERUSDT", "asset": "BURGER", "currency": "USDT", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "BURGER/USDT" }, { "id": "SLPBUSD", "asset": "SLP", "currency": "BUSD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "SLP/BUSD" }, { "id": "SLPUSDT", "asset": "SLP", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "SLP/USDT" }, { "id": "TRXAUD", "asset": "TRX", "currency": "AUD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "TRX/AUD" }, { "id": "TRXEUR", "asset": "TRX", "currency": "EUR", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "TRX/EUR" }, { "id": "VETTRY", "asset": "VET", "currency": "TRY", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "VET/TRY" }, { "id": "SHIBUSDT", "asset": "SHIB", "currency": "USDT", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "10.00000000", "increment": "0.00000001", "asset_increment": "1.00", "label": "SHIB/USDT" }, { "id": "SHIBBUSD", "asset": "SHIB", "currency": "BUSD", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "10.00000000", "increment": "0.00000001", "asset_increment": "1.00", "label": "SHIB/BUSD" }, { "id": "ICPBTC", "asset": "ICP", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "ICP/BTC" }, { "id": "ICPBNB", "asset": "ICP", "currency": "BNB", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ICP/BNB" }, { "id": "ICPBUSD", "asset": "ICP", "currency": "BUSD", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ICP/BUSD" }, { "id": "ICPUSDT", "asset": "ICP", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ICP/USDT" }, { "id": "BTCGYEN", "asset": "BTC", "currency": "GYEN", "min_size": "0.00001000", "max_size": "153.00000000", "min_total": "1000.00000000", "increment": "1.00000000", "asset_increment": "0.00001000", "label": "BTC/GYEN" }, { "id": "USDTGYEN", "asset": "USDT", "currency": "GYEN", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "1000.00000000", "increment": "0.01000000", "asset_increment": "0.10000000", "label": "USDT/GYEN" }, { "id": "SHIBEUR", "asset": "SHIB", "currency": "EUR", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "10.00000000", "increment": "0.00000001", "asset_increment": "1.00", "label": "SHIB/EUR" }, { "id": "SHIBRUB", "asset": "SHIB", "currency": "RUB", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "100.00000000", "increment": "0.00000100", "asset_increment": "1.00", "label": "SHIB/RUB" }, { "id": "ETCEUR", "asset": "ETC", "currency": "EUR", "min_size": "0.00100000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ETC/EUR" }, { "id": "ETCBRL", "asset": "ETC", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ETC/BRL" }, { "id": "DOGEBIDR", "asset": "DOGE", "currency": "BIDR", "min_size": "1.00000000", "max_size": "922327.00000000", "min_total": "20000.00", "increment": "0.01", "asset_increment": "1.00000000", "label": "DOGE/BIDR" }, { "id": "ARBTC", "asset": "AR", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "AR/BTC" }, { "id": "ARBNB", "asset": "AR", "currency": "BNB", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "AR/BNB" }, { "id": "ARBUSD", "asset": "AR", "currency": "BUSD", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "AR/BUSD" }, { "id": "ARUSDT", "asset": "AR", "currency": "USDT", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "AR/USDT" }, { "id": "POLSBTC", "asset": "POLS", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "POLS/BTC" }, { "id": "POLSBNB", "asset": "POLS", "currency": "BNB", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "POLS/BNB" }, { "id": "POLSBUSD", "asset": "POLS", "currency": "BUSD", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "POLS/BUSD" }, { "id": "POLSUSDT", "asset": "POLS", "currency": "USDT", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "POLS/USDT" }, { "id": "MDXBTC", "asset": "MDX", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "MDX/BTC" }, { "id": "MDXBNB", "asset": "MDX", "currency": "BNB", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "MDX/BNB" }, { "id": "MDXBUSD", "asset": "MDX", "currency": "BUSD", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MDX/BUSD" }, { "id": "MDXUSDT", "asset": "MDX", "currency": "USDT", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "MDX/USDT" }, { "id": "MASKBNB", "asset": "MASK", "currency": "BNB", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.01000000", "label": "MASK/BNB" }, { "id": "MASKBUSD", "asset": "MASK", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "MASK/BUSD" }, { "id": "MASKUSDT", "asset": "MASK", "currency": "USDT", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "MASK/USDT" }, { "id": "LPTBTC", "asset": "LPT", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141570.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "LPT/BTC" }, { "id": "LPTBNB", "asset": "LPT", "currency": "BNB", "min_size": "0.10000000", "max_size": "92141570.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "LPT/BNB" }, { "id": "LPTBUSD", "asset": "LPT", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222440.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "LPT/BUSD" }, { "id": "LPTUSDT", "asset": "LPT", "currency": "USDT", "min_size": "0.01000000", "max_size": "9222440.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "LPT/USDT" }, { "id": "ETHUAH", "asset": "ETH", "currency": "UAH", "min_size": "0.00000100", "max_size": "9220.00000000", "min_total": "100.00000000", "increment": "1.00000000", "asset_increment": "0.00000100", "label": "ETH/UAH" }, { "id": "MATICBRL", "asset": "MATIC", "currency": "BRL", "min_size": "0.01000000", "max_size": "9222440.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "MATIC/BRL" }, { "id": "SOLEUR", "asset": "SOL", "currency": "EUR", "min_size": "0.01000000", "max_size": "9222440.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "SOL/EUR" }, { "id": "SHIBBRL", "asset": "SHIB", "currency": "BRL", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "10.00000000", "increment": "0.00000001", "asset_increment": "1.00", "label": "SHIB/BRL" }, { "id": "AGIXBTC", "asset": "AGIX", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "AGIX/BTC" }, { "id": "ICPEUR", "asset": "ICP", "currency": "EUR", "min_size": "0.00100000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00100000", "label": "ICP/EUR" }, { "id": "MATICGBP", "asset": "MATIC", "currency": "GBP", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "MATIC/GBP" }, { "id": "SHIBTRY", "asset": "SHIB", "currency": "TRY", "min_size": "1.00", "max_size": "10000000000.00", "min_total": "10.00000000", "increment": "0.00000001", "asset_increment": "1.00", "label": "SHIB/TRY" }, { "id": "MATICBIDR", "asset": "MATIC", "currency": "BIDR", "min_size": "0.00010000", "max_size": "9223.00000000", "min_total": "20000.00", "increment": "1.00", "asset_increment": "0.00010000", "label": "MATIC/BIDR" }, { "id": "MATICRUB", "asset": "MATIC", "currency": "RUB", "min_size": "0.00010000", "max_size": "922327.00000000", "min_total": "100.00000000", "increment": "0.10000000", "asset_increment": "0.00010000", "label": "MATIC/RUB" }, { "id": "NUBTC", "asset": "NU", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.01000000", "label": "NU/BTC" }, { "id": "NUBNB", "asset": "NU", "currency": "BNB", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "NU/BNB" }, { "id": "NUBUSD", "asset": "NU", "currency": "BUSD", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "NU/BUSD" }, { "id": "NUUSDT", "asset": "NU", "currency": "USDT", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "NU/USDT" }, { "id": "XVGUSDT", "asset": "XVG", "currency": "USDT", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "XVG/USDT" }, { "id": "RLCBUSD", "asset": "RLC", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "RLC/BUSD" }, { "id": "CELRBUSD", "asset": "CELR", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "CELR/BUSD" }, { "id": "ATMBUSD", "asset": "ATM", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ATM/BUSD" }, { "id": "ZENBUSD", "asset": "ZEN", "currency": "BUSD", "min_size": "0.00100000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.10000000", "asset_increment": "0.00100000", "label": "ZEN/BUSD" }, { "id": "FTMBUSD", "asset": "FTM", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "FTM/BUSD" }, { "id": "THETABUSD", "asset": "THETA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "THETA/BUSD" }, { "id": "WINBUSD", "asset": "WIN", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "WIN/BUSD" }, { "id": "KAVABUSD", "asset": "KAVA", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.01000000", "label": "KAVA/BUSD" }, { "id": "XEMBUSD", "asset": "XEM", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "1.00000000", "label": "XEM/BUSD" }, { "id": "ATABTC", "asset": "ATA", "currency": "BTC", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ATA/BTC" }, { "id": "ATABNB", "asset": "ATA", "currency": "BNB", "min_size": "1.00000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "ATA/BNB" }, { "id": "ATABUSD", "asset": "ATA", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "ATA/BUSD" }, { "id": "ATAUSDT", "asset": "ATA", "currency": "USDT", "min_size": "1.00000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "1.00000000", "label": "ATA/USDT" }, { "id": "GTCBTC", "asset": "GTC", "currency": "BTC", "min_size": "0.01000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "GTC/BTC" }, { "id": "GTCBNB", "asset": "GTC", "currency": "BNB", "min_size": "0.10000000", "max_size": "92141578.00000000", "min_total": "0.05000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "GTC/BNB" }, { "id": "GTCBUSD", "asset": "GTC", "currency": "BUSD", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "GTC/BUSD" }, { "id": "GTCUSDT", "asset": "GTC", "currency": "USDT", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "GTC/USDT" }, { "id": "TORNBTC", "asset": "TORN", "currency": "BTC", "min_size": "0.00100000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.00100000", "label": "TORN/BTC" }, { "id": "TORNBNB", "asset": "TORN", "currency": "BNB", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "0.05000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "TORN/BNB" }, { "id": "TORNBUSD", "asset": "TORN", "currency": "BUSD", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "TORN/BUSD" }, { "id": "TORNUSDT", "asset": "TORN", "currency": "USDT", "min_size": "0.01000000", "max_size": "922327.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "TORN/USDT" }, { "id": "MATICTRY", "asset": "MATIC", "currency": "TRY", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.10000000", "label": "MATIC/TRY" }, { "id": "ETCGBP", "asset": "ETC", "currency": "GBP", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "ETC/GBP" }, { "id": "SOLGBP", "asset": "SOL", "currency": "GBP", "min_size": "0.01000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.01000000", "label": "SOL/GBP" }, { "id": "BAKEBTC", "asset": "BAKE", "currency": "BTC", "min_size": "0.10000000", "max_size": "92141578.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.10000000", "label": "BAKE/BTC" }, { "id": "COTIBUSD", "asset": "COTI", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9222449.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.10000000", "label": "COTI/BUSD" } ] ================================================ FILE: extensions/exchanges/binance/update-products.sh ================================================ #!/usr/bin/env node let ccxt = require('ccxt') new ccxt.binance().fetch_markets().then(function(markets) { var products = [] var products = markets.map(function (market) { const filters = market.info.filters const price_filter = filters.find(f => f.filterType === 'PRICE_FILTER') const lot_size_filter = filters.find(f => f.filterType === 'LOT_SIZE') const notional_filter = filters.find(f => f.filterType === 'MIN_NOTIONAL') // NOTE: price_filter also contains minPrice and maxPrice return { id: market.id, asset: market.base, currency: market.quote, min_size: lot_size_filter.minQty, max_size: lot_size_filter.maxQty, min_total: notional_filter.minNotional, increment: price_filter.tickSize, asset_increment: lot_size_filter.stepSize, label: market.base + '/' + market.quote } }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/binanceus/exchange.js ================================================ const ccxt = require('ccxt') , path = require('path') // eslint-disable-next-line no-unused-vars , colors = require('colors') , _ = require('lodash') module.exports = function binanceus (conf) { var public_client, authed_client function publicClient () { if (!public_client) public_client = new ccxt.binanceus({ 'apiKey': '', 'secret': '', 'options': { 'adjustForTimeDifference': true } }) return public_client } function authedClient () { if (!authed_client) { if (!conf.binanceus || !conf.binanceus.key || conf.binanceus.key === 'YOUR-API-KEY') { throw new Error('please configure your BinanceUS credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new ccxt.binanceus({ 'apiKey': conf.binanceus.key, 'secret': conf.binanceus.secret, 'options': { 'adjustForTimeDifference': true }, enableRateLimit: true }) } return authed_client } /** * Convert BNB-BTC to BNB/BTC * * @param product_id BNB-BTC * @returns {string} */ function joinProduct(product_id) { let split = product_id.split('-') return split[0] + '/' + split[1] } function retry (method, args, err) { if (method !== 'getTrades') { console.error(('\nBinanceUS API is down! unable to call ' + method + ', retrying in 20s').red) if (err) console.error(err) console.error(args.slice(0, -1)) } setTimeout(function () { exchange[method].apply(exchange, args) }, 20000) } var orders = {} var exchange = { name: 'binanceus', historyScan: 'forward', historyScanUsesTime: true, makerFee: 0.1, takerFee: 0.1, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() var startTime = null var args = {} if (opts.from) { startTime = opts.from } else { startTime = parseInt(opts.to, 10) - 3600000 args['endTime'] = opts.to } const symbol = joinProduct(opts.product_id) client.fetchTrades(symbol, startTime, undefined, args).then(result => { if (result.length === 0 && opts.from) { // client.fetchTrades() only returns trades in an 1 hour interval. // So we use fetchOHLCV() to detect trade appart from more than 1h. // Note: it's done only in forward mode. const time_diff = client.options['timeDifference'] if (startTime + time_diff < (new Date()).getTime() - 3600000) { // startTime is older than 1 hour ago. return client.fetchOHLCV(symbol, undefined, startTime) .then(ohlcv => { return ohlcv.length ? client.fetchTrades(symbol, ohlcv[0][0]) : [] }) } } return result }).then(result => { var trades = result.map(trade => ({ trade_id: trade.id, time: trade.timestamp, size: parseFloat(trade.amount), price: parseFloat(trade.price), side: trade.side })) cb(null, trades) }).catch(function (error) { console.error('An error occurred', error) return retry('getTrades', func_args) }) }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.fetchBalance().then(result => { var balance = {asset: 0, currency: 0} Object.keys(result).forEach(function (key) { if (key === opts.currency) { balance.currency = result[key].free + result[key].used balance.currency_hold = result[key].used } if (key === opts.asset) { balance.asset = result[key].free + result[key].used balance.asset_hold = result[key].used } }) cb(null, balance) }) .catch(function (error) { console.error('An error occurred', error) return retry('getBalance', func_args) }) }, getQuote: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchTicker(joinProduct(opts.product_id)).then(result => { cb(null, { bid: result.bid, ask: result.ask }) }) .catch(function (error) { console.error('An error occurred', error) return retry('getQuote', func_args) }) }, getDepth: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchOrderBook(joinProduct(opts.product_id), {limit: opts.limit}).then(result => { cb(null, result) }) .catch(function(error) { console.error('An error ocurred', error) return retry('getDepth', func_args) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.cancelOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { if (body && (body.message === 'Order already done' || body.message === 'order not found')) return cb() cb(null) }, function(err){ // match error against string: // "binanceus {"code":-2011,"msg":"UNKNOWN_ORDER"}" if (err) { // decide if this error is allowed for a retry if (err.message && err.message.match(new RegExp(/-2011|UNKNOWN_ORDER/))) { console.error(('\ncancelOrder retry - unknown Order: ' + JSON.stringify(opts) + ' - ' + err).cyan) } else { // retry is allowed for this error return retry('cancelOrder', func_args, err) } } cb() }) }, buy: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } opts.type = 'limit' var args = {} if (opts.order_type === 'taker') { delete opts.price delete opts.post_only opts.type = 'market' } else { args.timeInForce = 'GTC' } opts.side = 'buy' delete opts.order_type var order = {} client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { if (result && result.message === 'Insufficient funds') { order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } order = { id: result ? result.id : null, status: 'open', price: opts.price, size: this.roundToNearest(opts.size, opts), post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } orders['~' + result.id] = order cb(null, order) }).catch(function (error) { console.error('An error occurred', error) // decide if this error is allowed for a retry: // {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"} // {"code":-2010,"msg":"Account has insufficient balance for requested action"} if (error.message.match(new RegExp(/-1013|MIN_NOTIONAL|-2010/))) { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } return retry('buy', func_args) }) }, sell: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } opts.type = 'limit' var args = {} if (opts.order_type === 'taker') { delete opts.price delete opts.post_only opts.type = 'market' } else { args.timeInForce = 'GTC' } opts.side = 'sell' delete opts.order_type var order = {} client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { if (result && result.message === 'Insufficient funds') { order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } order = { id: result ? result.id : null, status: 'open', price: opts.price, size: this.roundToNearest(opts.size, opts), post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } orders['~' + result.id] = order cb(null, order) }).catch(function (error) { console.error('An error occurred', error) // decide if this error is allowed for a retry: // {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"} // {"code":-2010,"msg":"Account has insufficient balance for requested action"} if (error.message.match(new RegExp(/-1013|MIN_NOTIONAL|-2010/))) { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } return retry('sell', func_args) }) }, roundToNearest: function(numToRound, opts) { var numToRoundTo = _.find(this.getProducts(), { 'asset': opts.product_id.split('-')[0], 'currency': opts.product_id.split('-')[1] }).min_size numToRoundTo = 1 / (numToRoundTo) return Math.floor(numToRound * numToRoundTo) / numToRoundTo }, getOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() var order = orders['~' + opts.order_id] client.fetchOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { if (body.status !== 'open' && body.status !== 'canceled') { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = parseFloat(body.amount) - parseFloat(body.remaining) return cb(null, order) } cb(null, order) }, function(err) { return retry('getOrder', func_args, err) }) }, getCursor: function (trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/binanceus/products.json ================================================ [ { "id": "BTCUSD", "asset": "BTC", "currency": "USD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00000100", "label": "BTC/USD" }, { "id": "ETHUSD", "asset": "ETH", "currency": "USD", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "ETH/USD" }, { "id": "XRPUSD", "asset": "XRP", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "XRP/USD" }, { "id": "BCHUSD", "asset": "BCH", "currency": "USD", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "BCH/USD" }, { "id": "LTCUSD", "asset": "LTC", "currency": "USD", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "LTC/USD" }, { "id": "USDTUSD", "asset": "USDT", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "USDT/USD" }, { "id": "BTCUSDT", "asset": "BTC", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/USDT" }, { "id": "ETHUSDT", "asset": "ETH", "currency": "USDT", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/USDT" }, { "id": "XRPUSDT", "asset": "XRP", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XRP/USDT" }, { "id": "BCHUSDT", "asset": "BCH", "currency": "USDT", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "BCH/USDT" }, { "id": "LTCUSDT", "asset": "LTC", "currency": "USDT", "min_size": "0.00001000", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "LTC/USDT" }, { "id": "BNBUSD", "asset": "BNB", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "BNB/USD" }, { "id": "BNBUSDT", "asset": "BNB", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BNB/USDT" }, { "id": "ETHBTC", "asset": "ETH", "currency": "BTC", "min_size": "0.00100000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "ETH/BTC" }, { "id": "XRPBTC", "asset": "XRP", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "XRP/BTC" }, { "id": "BNBBTC", "asset": "BNB", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "BNB/BTC" }, { "id": "LTCBTC", "asset": "LTC", "currency": "BTC", "min_size": "0.01000000", "max_size": "100000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.01000000", "label": "LTC/BTC" }, { "id": "BCHBTC", "asset": "BCH", "currency": "BTC", "min_size": "0.00100000", "max_size": "10000000.00000000", "min_total": "0.00010000", "increment": "0.00000100", "asset_increment": "0.00100000", "label": "BCH/BTC" }, { "id": "ADAUSD", "asset": "ADA", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "ADA/USD" }, { "id": "BATUSD", "asset": "BAT", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "BAT/USD" }, { "id": "ETCUSD", "asset": "ETC", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "ETC/USD" }, { "id": "XLMUSD", "asset": "XLM", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "XLM/USD" }, { "id": "ZRXUSD", "asset": "ZRX", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "ZRX/USD" }, { "id": "ADAUSDT", "asset": "ADA", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ADA/USDT" }, { "id": "BATUSDT", "asset": "BAT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAT/USDT" }, { "id": "ETCUSDT", "asset": "ETC", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ETC/USDT" }, { "id": "XLMUSDT", "asset": "XLM", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XLM/USDT" }, { "id": "ZRXUSDT", "asset": "ZRX", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ZRX/USDT" }, { "id": "LINKUSD", "asset": "LINK", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "LINK/USD" }, { "id": "RVNUSD", "asset": "RVN", "currency": "USD", "min_size": "0.10000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "RVN/USD" }, { "id": "DASHUSD", "asset": "DASH", "currency": "USD", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "DASH/USD" }, { "id": "ZECUSD", "asset": "ZEC", "currency": "USD", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "ZEC/USD" }, { "id": "ALGOUSD", "asset": "ALGO", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "ALGO/USD" }, { "id": "IOTAUSD", "asset": "IOTA", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "IOTA/USD" }, { "id": "BUSDUSD", "asset": "BUSD", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "BUSD/USD" }, { "id": "BTCBUSD", "asset": "BTC", "currency": "BUSD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/BUSD" }, { "id": "DOGEUSDT", "asset": "DOGE", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000010", "asset_increment": "1.00000000", "label": "DOGE/USDT" }, { "id": "WAVESUSD", "asset": "WAVES", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "WAVES/USD" }, { "id": "ATOMUSDT", "asset": "ATOM", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ATOM/USDT" }, { "id": "ATOMUSD", "asset": "ATOM", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "ATOM/USD" }, { "id": "NEOUSDT", "asset": "NEO", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "NEO/USDT" }, { "id": "NEOUSD", "asset": "NEO", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "NEO/USD" }, { "id": "VETUSDT", "asset": "VET", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "VET/USDT" }, { "id": "QTUMUSDT", "asset": "QTUM", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "QTUM/USDT" }, { "id": "QTUMUSD", "asset": "QTUM", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "QTUM/USD" }, { "id": "NANOUSD", "asset": "NANO", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "NANO/USD" }, { "id": "ICXUSD", "asset": "ICX", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "ICX/USD" }, { "id": "ENJUSD", "asset": "ENJ", "currency": "USD", "min_size": "0.10000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "ENJ/USD" }, { "id": "ONTUSD", "asset": "ONT", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "ONT/USD" }, { "id": "ONTUSDT", "asset": "ONT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ONT/USDT" }, { "id": "ZILUSD", "asset": "ZIL", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "ZIL/USD" }, { "id": "ZILBUSD", "asset": "ZIL", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ZIL/BUSD" }, { "id": "VETUSD", "asset": "VET", "currency": "USD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "1.00000000", "label": "VET/USD" }, { "id": "BNBBUSD", "asset": "BNB", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BNB/BUSD" }, { "id": "XRPBUSD", "asset": "XRP", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "XRP/BUSD" }, { "id": "ETHBUSD", "asset": "ETH", "currency": "BUSD", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "ETH/BUSD" }, { "id": "ALGOBUSD", "asset": "ALGO", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "ALGO/BUSD" }, { "id": "XTZUSD", "asset": "XTZ", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "XTZ/USD" }, { "id": "XTZBUSD", "asset": "XTZ", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "XTZ/BUSD" }, { "id": "HBARUSD", "asset": "HBAR", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "HBAR/USD" }, { "id": "HBARBUSD", "asset": "HBAR", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HBAR/BUSD" }, { "id": "OMGUSD", "asset": "OMG", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "OMG/USD" }, { "id": "OMGBUSD", "asset": "OMG", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OMG/BUSD" }, { "id": "MATICUSD", "asset": "MATIC", "currency": "USD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "MATIC/USD" }, { "id": "MATICBUSD", "asset": "MATIC", "currency": "BUSD", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "MATIC/BUSD" }, { "id": "XTZBTC", "asset": "XTZ", "currency": "BTC", "min_size": "0.01000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000010", "asset_increment": "0.01000000", "label": "XTZ/BTC" }, { "id": "ADABTC", "asset": "ADA", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "ADA/BTC" }, { "id": "REPBUSD", "asset": "REP", "currency": "BUSD", "min_size": "0.00100000", "max_size": "1000000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00100000", "label": "REP/BUSD" }, { "id": "REPUSD", "asset": "REP", "currency": "USD", "min_size": "0.00100000", "max_size": "1000000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00100000", "label": "REP/USD" }, { "id": "EOSBUSD", "asset": "EOS", "currency": "BUSD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "EOS/BUSD" }, { "id": "EOSUSD", "asset": "EOS", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "EOS/USD" }, { "id": "DOGEUSD", "asset": "DOGE", "currency": "USD", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "1.00000000", "label": "DOGE/USD" }, { "id": "KNCUSD", "asset": "KNC", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "KNC/USD" }, { "id": "KNCUSDT", "asset": "KNC", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "KNC/USDT" }, { "id": "VTHOUSDT", "asset": "VTHO", "currency": "USDT", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "VTHO/USDT" }, { "id": "VTHOUSD", "asset": "VTHO", "currency": "USD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "1.00000000", "label": "VTHO/USD" }, { "id": "USDCUSD", "asset": "USDC", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "USDC/USD" }, { "id": "COMPUSDT", "asset": "COMP", "currency": "USDT", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "COMP/USDT" }, { "id": "COMPUSD", "asset": "COMP", "currency": "USD", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00001000", "label": "COMP/USD" }, { "id": "MANAUSD", "asset": "MANA", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "MANA/USD" }, { "id": "HNTUSD", "asset": "HNT", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "HNT/USD" }, { "id": "HNTUSDT", "asset": "HNT", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "HNT/USDT" }, { "id": "MKRUSD", "asset": "MKR", "currency": "USD", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.00001000", "label": "MKR/USD" }, { "id": "MKRUSDT", "asset": "MKR", "currency": "USDT", "min_size": "0.00001000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00001000", "label": "MKR/USDT" }, { "id": "DAIUSD", "asset": "DAI", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "DAI/USD" }, { "id": "ONEUSDT", "asset": "ONE", "currency": "USDT", "min_size": "0.10000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00001000", "asset_increment": "0.10000000", "label": "ONE/USDT" }, { "id": "ONEUSD", "asset": "ONE", "currency": "USD", "min_size": "0.10000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.10000000", "label": "ONE/USD" }, { "id": "BANDUSDT", "asset": "BAND", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BAND/USDT" }, { "id": "BANDUSD", "asset": "BAND", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "BAND/USD" }, { "id": "STORJUSDT", "asset": "STORJ", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "STORJ/USDT" }, { "id": "STORJUSD", "asset": "STORJ", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "STORJ/USD" }, { "id": "BUSDUSDT", "asset": "BUSD", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "BUSD/USDT" }, { "id": "UNIUSD", "asset": "UNI", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "UNI/USD" }, { "id": "UNIUSDT", "asset": "UNI", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "UNI/USDT" }, { "id": "SOLUSD", "asset": "SOL", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "SOL/USD" }, { "id": "SOLUSDT", "asset": "SOL", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "SOL/USDT" }, { "id": "LINKBTC", "asset": "LINK", "currency": "BTC", "min_size": "0.10000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "0.10000000", "label": "LINK/BTC" }, { "id": "VETBTC", "asset": "VET", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "VET/BTC" }, { "id": "UNIBTC", "asset": "UNI", "currency": "BTC", "min_size": "1.00000000", "max_size": "90000000.00000000", "min_total": "0.00010000", "increment": "0.00000001", "asset_increment": "1.00000000", "label": "UNI/BTC" }, { "id": "EGLDUSDT", "asset": "EGLD", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "EGLD/USDT" }, { "id": "EGLDUSD", "asset": "EGLD", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "EGLD/USD" }, { "id": "PAXGUSDT", "asset": "PAXG", "currency": "USDT", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "PAXG/USDT" }, { "id": "PAXGUSD", "asset": "PAXG", "currency": "USD", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.0000", "increment": "0.0100", "asset_increment": "0.00000100", "label": "PAXG/USD" }, { "id": "OXTUSDT", "asset": "OXT", "currency": "USDT", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00010000", "asset_increment": "0.01000000", "label": "OXT/USDT" }, { "id": "OXTUSD", "asset": "OXT", "currency": "USD", "min_size": "0.01000000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0001", "asset_increment": "0.01000000", "label": "OXT/USD" }, { "id": "ZENUSDT", "asset": "ZEN", "currency": "USDT", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.00000000", "increment": "0.00100000", "asset_increment": "0.00100000", "label": "ZEN/USDT" }, { "id": "ZENUSD", "asset": "ZEN", "currency": "USD", "min_size": "0.00100000", "max_size": "900000.00000000", "min_total": "10.0000", "increment": "0.0010", "asset_increment": "0.00100000", "label": "ZEN/USD" }, { "id": "BTCUSDC", "asset": "BTC", "currency": "USDC", "min_size": "0.00000100", "max_size": "9000.00000000", "min_total": "10.00000000", "increment": "0.01000000", "asset_increment": "0.00000100", "label": "BTC/USDC" }, { "id": "ONEBUSD", "asset": "ONE", "currency": "BUSD", "min_size": "1.00000000", "max_size": "9000000.00000000", "min_total": "10.00000000", "increment": "0.00000100", "asset_increment": "1.00000000", "label": "ONE/BUSD" } ] ================================================ FILE: extensions/exchanges/binanceus/update-products.sh ================================================ #!/usr/bin/env node let ccxt = require('ccxt') new ccxt.binanceus().fetch_markets().then(function(markets) { var products = [] var products = markets.map(function (market) { const filters = market.info.filters const price_filter = filters.find(f => f.filterType === 'PRICE_FILTER') const lot_size_filter = filters.find(f => f.filterType === 'LOT_SIZE') const notional_filter = filters.find(f => f.filterType === 'MIN_NOTIONAL') // NOTE: price_filter also contains minPrice and maxPrice return { id: market.id, asset: market.base, currency: market.quote, min_size: lot_size_filter.minQty, max_size: lot_size_filter.maxQty, min_total: notional_filter.minNotional, increment: price_filter.tickSize, asset_increment: lot_size_filter.stepSize, label: market.base + '/' + market.quote } }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/bitfinex/exchange.js ================================================ const BFX = require('bitfinex-api-node') var minimist = require('minimist') , path = require('path') , n = require('numbro') module.exports = function bitfinex(conf) { var s = { options: minimist(process.argv) } var so = s.options var ws_connecting = false var ws_connected = false var ws_timeout = 60000 var ws_retry = 10000 const getTrades_timeout = 2000 var pair, public_client, ws_client var ws_trades = [] var ws_balance = [] var ws_orders = [] var ws_ticker = [] var ws_hb = [] var ws_walletCalcDone = [] var heartbeat_interval function publicClient() { if (!public_client) public_client = new BFX().rest(2, { transform: true }) return public_client } function wsUpdateTrades(pair, trades) { trades.forEach(function (trade) { var newTrade = { trade_id: Number(trade.id), time: Number(trade.mts), size: Math.abs(trade.amount), price: Number(trade.price), side: trade.amount > 0 ? 'buy' : 'sell' } ws_trades.push(newTrade) }) if (ws_trades.length > 1010) ws_trades.shift() } function wsUpdateTicker(pair, ticker) { ws_ticker = ticker } function wsMessage(message) { console.log(message) if (message[0] != 'undefined') ws_hb[message[0]] = Date.now() } function wsUpdateOrder(ws_order) { var cid = ws_order[2] // https://bitfinex.readme.io/v2/reference#ws-auth-orders var order = ws_orders['~' + cid] if (!order) { if (so.debug) console.warn(('\nWarning: Order ' + cid + ' not found in cache for wsUpdateOrder (manual order?).').red) return } if (ws_order[13] === 'ACTIVE' || ws_order[13].match(/^PARTIALLY FILLED/)) { order.status = 'open' } else if (ws_order[13].match(/^EXECUTED/)) { order.status = 'done' } else if (ws_order[13] === 'CANCELED') { order.status = 'rejected' } else if (ws_order[13] === 'POSTONLY CANCELED') { order.status = 'rejected' order.reject_reason = 'post only' } order.bitfinex_id = ws_order[0] order.created_at = ws_order[4] order.filled_size = n(ws_order[7]).subtract(ws_order[6]).format('0.00000000') order.bitfinex_status = ws_order[13] order.price = ws_order[16] order.price_avg = ws_order[17] ws_orders['~' + cid] = order } function wsUpdateOrderCancel(ws_order) { var cid = ws_order[2] if (!ws_orders['~' + cid]) { if (so.debug) console.warn(('\nWarning: Order ' + cid + ' not found in cache for wsUpdateOrderCancel (manual order?).').red) return } if (ws_order[13].match(/^INSUFFICIENT MARGIN/)) { ws_orders['~' + cid].status = 'rejected' ws_orders['~' + cid].reject_reason = 'balance' } setTimeout(function () { delete (ws_orders['~' + cid]) }, 60000 * 60 * 12) wsUpdateOrder(ws_order) } function wsUpdateReqOrder(error) { if (error[6] === 'ERROR' && error[7].match(/^Invalid order: not enough .* balance for/)) { var cid = error[4][2] if (!ws_orders['~' + cid]) { if (so.debug) console.warn(('\nWarning: Order ' + cid + ' not found in cache for wsUpdateReqOrder (manual order?).').red) return } ws_orders['~' + cid].status = 'rejected' ws_orders['~' + cid].reject_reason = 'balance' } if (error[6] === 'ERROR' && error[7] === 'Invalid price.') { cid = error[4][2] if (!ws_orders['~' + cid]) { if (so.debug) console.warn(('\nWarning: Order ' + cid + ' not found in cache for wsUpdateReqOrder (manual order?).').red) return } if (so.debug) console.log(ws_orders['~' + cid]) ws_orders['~' + cid].status = 'rejected' ws_orders['~' + cid].reject_reason = 'price' } } function updateWallet(wallets) { if (typeof (wallets[0]) !== 'object') wallets = [wallets] wallets.forEach(function (wallet) { if (wallet['type'] === conf.bitfinex.wallet) { ws_balance[wallet['currency'].toUpperCase()] = {} ws_balance[wallet['currency'].toUpperCase()].balance = wallet['balance'] ws_balance[wallet['currency'].toUpperCase()].available = wallet['balanceAvailable'] ? wallet['balanceAvailable'] : 0 ws_balance[wallet['currency'].toUpperCase()].wallet = wallet['type'] if (wallet['balanceAvailable'] !== null) { ws_walletCalcDone[wallet['currency']] = true } } }) } function wsConnect() { if (ws_connected || ws_connecting) return ws_client.open() ws_connecting = true } function wsSubscribed(event) { // We only use the 'trades' channel for heartbeats. That one should be most frequently updated. if (event.channel === 'trades') { ws_hb[event.chanId] = Date.now() heartbeat_interval = setInterval(function () { if (ws_hb[event.chanId]) { var timeoutThreshold = (Number(Date.now()) - ws_timeout) if (timeoutThreshold > ws_hb[event.chanId]) { console.warn(('\nWebSockets Warning: No message on channel \'trade\' within ' + ws_timeout / 1000 + ' seconds, reconnecting...').red) ws_client.close() } } }, ws_timeout) } } function wsClose() { ws_connecting = false ws_connected = false clearInterval(heartbeat_interval) console.error(('\nWebSockets Error: Connection closed.').red + ' Retrying every ' + (ws_retry / 1000 + ' seconds').yellow + '.') } function wsError(e) { console.warn(e) ws_connecting = false ws_connected = false if (e.event == 'auth' && e.status == 'FAILED') { var errorMessage = ('\nWebSockets Warning: Authentication ' + e.status + ' (Reason: "' + e.msg + '").').red if (e.msg == 'apikey: invalid') errorMessage = errorMessage + '\nEither your API key is invalid or you tried reconnecting to quickly. Wait and/or check your API keys.' console.warn(errorMessage) ws_client.close() } else { ws_client.close() } } function wsClient() { if (!ws_client) { if (!conf.bitfinex || !conf.bitfinex.key || conf.bitfinex.key === 'YOUR-API-KEY') { throw new Error('please configure your Bitfinex credentials in ' + path.resolve(__dirname, 'conf.js')) } ws_connected = false ws_client = new BFX({ apiKey: conf.bitfinex.key, apiSecret: conf.bitfinex.secret, transform: true }).ws() ws_client.on('error', (err) => wsError(err)) ws_client.on('open', ws_client.auth.bind(ws_client)) ws_client.on('close', wsClose) ws_client.on('subscribed', wsSubscribed) ws_client.once('auth', () => { if (so.debug) { console.log(('\nWebSockets: We are now fully connected and authenticated.').green) } ws_connecting = false ws_connected = true ws_client.subscribeTrades(pair) ws_client.subscribeTicker(pair) ws_client.onWalletSnapshot({}, (wallets) => updateWallet(wallets)) ws_client.onWalletUpdate({}, (wallets) => updateWallet(wallets)) ws_client.onTicker({}, (ticker) => wsUpdateTicker(pair, ticker)) ws_client.onMessage({}, (msg) => wsMessage(msg)) ws_client.onTrades({}, (trades) => wsUpdateTrades(pair, trades)) ws_client.onOrderUpdate({}, (order) => { if (order['type'] == 'oc') { wsUpdateOrderCancel(order) } else { wsUpdateOrder(order) } }) ws_client.onMarginInfoUpdate({}, (symbol) => marginSymbolWebsocket(symbol)) ws_client.onPositionSnapshot({}, (positions) => assetPositionMargin(positions)) ws_client.onNotification({ type: 'on-req' }, (order) => wsUpdateReqOrder(order)) }) // we need also more position updates here, but messages are completely undocumented // https://bitfinex.readme.io/v1/reference#ws-auth-position-updates // possible only "pu" for update setInterval(function () { wsConnect() }, ws_retry) } } /** * * @param position ['tXRPUSD'] * @returns {string} */ function assetPositionMarginAssetExtract(position) { let pair = position[0] // tXRPUSD if (pair.substring(0, 1) === 't') { pair = pair.substring(1) } return pair.substring(0, pair.length - 3) } /** * We have no wallet on margin orders; fake current asset capital via open position * * @param positions * @see https://bitfinex.readme.io/v1/reference#ws-auth-position-snapshot */ function assetPositionMargin(positions) { // skip non margin if (conf.bitfinex.wallet !== 'margin') { return } // current positions in request // we need it for clear let assets = [] positions.filter(function (position) { return position.length > 2 }).forEach(function (position) { let asset = assetPositionMarginAssetExtract(position) if (!ws_balance[asset]) { ws_balance[asset] = {} } assets.push(asset) let action = position[1].toLowerCase() if (action === 'active') { ws_balance[asset].balance = position[2] ws_balance[asset].available = position[2] ws_balance[asset].wallet = 'margin' } else if (action === 'closed') { ws_balance[asset].balance = 0 ws_balance[asset].available = 0 ws_balance[asset].wallet = 'margin' } }) // clear non open positions; which are not existing anymore for (let key in ws_balance) { if (assets.indexOf(key) < 0 && ws_balance[key]) { ws_balance[key].balance = 0 ws_balance[key].available = 0 if (so.debug) { console.log('Clear asset: ' + JSON.stringify(ws_balance[key])) } } } } function joinProduct(product_id) { return product_id.split('-')[0] + '' + product_id.split('-')[1] } function retry(method, args, cb) { setTimeout(function () { exchange[method].call(exchange, args, cb) }, ws_retry) } function waitForCalc(method, args, cb) { setTimeout(function () { exchange[method].call(exchange, args, cb) }, 50) } function marginSymbolWebsocket(symbol) { /* [ 'sym', 'tBTCUSD', [ 101.11144665, // "all" - "active positions" 179.11144665, // "all" 78.11144665, // "all" - "active positions" - "active unfilled orders" 78.11144665, // "all" - "active positions" - "active unfilled orders" ? null, null, null, null ] */ if (symbol[0] !== 'sym') { return } // tBTCUSD if (symbol[1].substring(0, 1) !== 't') { return } let pair = symbol[1].substring(1) // not nice but values are not splitted // "tBTCUSD" extract => "USD" // "tDASHUSD" extract => "USD" let currency = symbol[1].substring(symbol[1].length - 3) // which array index to use to get available balance? :) ws_balance[currency].available = symbol[2][0] ws_balance[currency].balance = symbol[2][0] ws_walletCalcDone[pair] = true } function updateBalance(opts) { switch (conf.bitfinex.wallet) { case 'margin': try { ws_walletCalcDone[opts.asset] = 'inProgress' ws_walletCalcDone[opts.currency] = 'inProgress' ws_client.send([0, 'calc', null, [ ['margin_base'], ['margin_sym_' + opts.asset.toUpperCase() + opts.currency.toUpperCase()], ['funding_sym_' + opts.currency.toUpperCase()], ]]) } catch (e) { if (so.debug) { console.warn(e) console.warn(('\nWebSockets Warning: Cannot send \'calc\' for getBalance update (maybe connection not open?).').red + ' Waiting for reconnect.') } } break case 'exchange': try { ws_walletCalcDone[opts.asset] = 'inProgress' ws_walletCalcDone[opts.currency] = 'inProgress' ws_client.send([0, 'calc', null, [ ['wallet_exchange_' + opts.currency], ['wallet_exchange_' + opts.asset] ]]) } catch (e) { if (so.debug) { console.warn(e) console.warn(('\nWebSockets Warning: Cannot send \'calc\' for getBalance update (maybe connection not open?).').red + ' Waiting for reconnect.') } } break default: console.log('not supported wallet:' + opts.wallet) } } var exchange = { name: 'bitfinex', historyScan: 'backward', historyScanUsesTime: true, makerFee: 0.1, takerFee: 0.2, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { if (!pair) { pair = joinProduct(opts.product_id) } // Backfilling using the REST API if (opts.to || opts.to === null) { setTimeout(function () { var client = publicClient() var args = {} args.sort = -1 //backward args.limit = 1000 //this is max if (opts.from) { args.start = opts.from } else if (opts.to) { args.end = opts.to } else if (args.start && !args.end) { args.end = args.start + 500000 } else if (args.end && !args.start) { args.start = args.end - 500000 } const tpair = 't' + joinProduct(opts.product_id) client.trades(tpair, args.start, args.end, args.limit, args.sort, function (err, body) { if (err) { if (err.statusCode !== 500) { console.log(err.message, 'retrying...') return retry('getTrades', opts, cb) } else { cb(err) } } var trades = body.map(function (trade) { return { trade_id: trade.id, time: trade.mts, size: Math.abs(trade.amount), price: trade.price, side: trade.amount > 0 ? 'buy' : 'sell' } }) if (so.debug && trades.length > 0) console.log(new Date().toISOString(), 'got trade count ', trades.length, ' range: ', new Date(trades[trades.length - 1].time).toISOString(), '-', new Date(trades[0].time).toISOString()) cb(null, trades) }) // only 1 request per second allowed https://bitcoin.stackexchange.com/questions/36952/bitfinex-api-limit // but during testing I have discovered that 1 second is not enough, so double timeout looks better }, getTrades_timeout) } else { // We're live now (i.e. opts.from is set), use websockets if (!ws_client) { wsClient() } if (typeof (ws_trades) === 'undefined') { return retry('getTrades', opts, cb) } var trades = ws_trades.filter(function (trade) { return trade.time >= opts.from }) cb(null, trades) } }, getBalance: function (opts, cb) { if (!pair) { pair = joinProduct(opts.asset + '-' + opts.currency) } if (pair && !ws_walletCalcDone) { ws_walletCalcDone = {} ws_walletCalcDone[opts.asset] = false ws_walletCalcDone[opts.currency] = false } if (!ws_client) { wsClient() } if (Object.keys(ws_balance).length === 0) { if (so.debug && ws_connected === true) { console.warn(('WebSockets Warning: Waiting for initial websockets snapshot.').red + ' Retrying in ' + (ws_retry / 1000 + ' seconds').yellow + '.') } return retry('getBalance', opts, cb) } if (ws_walletCalcDone[opts.asset] === false && ws_walletCalcDone[opts.currency] === false) { updateBalance(opts) return waitForCalc('getBalance', opts, cb) } else if ( (ws_walletCalcDone[opts.asset] === false && ws_walletCalcDone[opts.currency] === true) || (ws_walletCalcDone[opts.asset] === true && ws_walletCalcDone[opts.currency] === false) ) { return waitForCalc('getBalance', opts, cb) } else { let balance = {} balance.currency = ws_balance[opts.currency] && ws_balance[opts.currency].balance ? n(ws_balance[opts.currency].balance).format('0.00000000') : n(0).format('0.00000000') balance.asset = ws_balance[opts.asset] && ws_balance[opts.asset].balance ? n(ws_balance[opts.asset].balance).format('0.00000000') : n(0).format('0.00000000') balance.currency_hold = ws_balance[opts.currency] && ws_balance[opts.currency].available ? n(ws_balance[opts.currency].balance).subtract(ws_balance[opts.currency].available).format('0.00000000') : n(0).format('0.00000000') balance.asset_hold = ws_balance[opts.asset] && ws_balance[opts.asset].available ? n(ws_balance[opts.asset].balance).subtract(ws_balance[opts.asset].available).format('0.00000000') : n(0).format('0.00000000') ws_walletCalcDone[opts.asset] = false ws_walletCalcDone[opts.currency] = false cb(null, balance) } }, getQuote: function (opts, cb) { cb(null, { bid: String(ws_ticker.bid), ask: String(ws_ticker.ask) }) }, cancelOrder: function (opts, cb) { var order = ws_orders['~' + opts.order_id] ws_orders['~' + opts.order_id].reject_reason = 'zenbot cancel' var ws_cancel_order = [ 0, 'oc', null, { id: order.bitfinex_id } ] try { ws_client.send(ws_cancel_order) } catch (e) { if (so.debug) { console.warn(e) console.warn(('\nWebSockets Warning: Cannot send cancelOrder (maybe connection not open?).').red + ' Retrying in ' + (ws_retry / 1000 + ' seconds').yellow + '.') } return retry('cancelOrder', opts, cb) } cb() }, trade: function (action, opts, cb) { if (!pair) { pair = joinProduct(opts.product_id) } var symbol = 't' + pair if (!ws_client) { wsClient() } var cid = Math.round(((new Date()).getTime()).toString() * Math.random()) var amount = action === 'buy' ? opts.size : opts.size * -1 var price = opts.price // only exchange need a prefix; no needed for margin let walletName = conf.bitfinex.wallet.toUpperCase() === 'EXCHANGE' ? 'EXCHANGE ' : '' if (opts.order_type === 'maker' && typeof opts.type === 'undefined') { opts.type = walletName + 'LIMIT' } else if (opts.order_type === 'taker' && typeof opts.type === 'undefined') { opts.type = walletName + 'MARKET' } if (typeof opts.post_only === 'undefined') { opts.post_only = true } var type = opts.type var is_postonly = opts.post_only var order = { id: cid, bitfinex_id: null, status: 'open', price: opts.price, size: opts.size, post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: 0, ordertype: opts.order_type } var ws_order = [ 0, 'on', null, { cid: cid, type: type, symbol: symbol, amount: String(amount), price: price, hidden: 0, postonly: is_postonly ? 1 : 0 } ] try { ws_client.send(ws_order) } catch (e) { if (so.debug) { console.warn(e) console.warn(('\nWebSockets Warning: Cannot send trade (maybe connection not open?).').red + (' Orders are sensitive, we\'re marking this one as rejected and will not just repeat the order automatically.').yellow) } order.status = 'rejected' order.reject_reason = 'could not send order over websockets' } ws_orders['~' + cid] = order return cb(null, order) }, buy: function (opts, cb) { exchange.trade('buy', opts, cb) }, sell: function (opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function (opts, cb) { var order = ws_orders['~' + opts.order_id] if (!order) { return cb(new Error('order id ' + opts.order_id + ' not found')) } if (order.status === 'rejected' && order.reject_reason === 'post only') { return cb(null, order) } else if (order.status === 'rejected' && order.reject_reason === 'zenbot canceled') { return cb(null, order) } if (order.status == 'done') { order.done_at = new Date().getTime() return cb(null, order) } cb(null, order) }, // return the property used for range querying. getCursor: function (trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/bitfinex/products.json ================================================ [ { "asset": "BTC", "currency": "USD", "min_size": "0.0002", "max_size": "2000.0", "increment": "0.001", "label": "BTC/USD" }, { "asset": "LTC", "currency": "USD", "min_size": "0.04", "max_size": "5000.0", "increment": "0.001", "label": "LTC/USD" }, { "asset": "LTC", "currency": "BTC", "min_size": "0.04", "max_size": "5000.0", "increment": "0.000001", "label": "LTC/BTC" }, { "asset": "ETH", "currency": "USD", "min_size": "0.006", "max_size": "5000.0", "increment": "0.001", "label": "ETH/USD" }, { "asset": "ETH", "currency": "BTC", "min_size": "0.006", "max_size": "5000.0", "increment": "0.000001", "label": "ETH/BTC" }, { "asset": "ETC", "currency": "BTC", "min_size": "0.4", "max_size": "100000.0", "increment": "0.0000001", "label": "ETC/BTC" }, { "asset": "ETC", "currency": "USD", "min_size": "0.4", "max_size": "100000.0", "increment": "0.0001", "label": "ETC/USD" }, { "asset": "RRT", "currency": "USD", "min_size": "62.0", "max_size": "100000.0", "increment": "0.000001", "label": "RRT/USD" }, { "asset": "ZEC", "currency": "USD", "min_size": "0.04", "max_size": "20000.0", "increment": "0.001", "label": "ZEC/USD" }, { "asset": "ZEC", "currency": "BTC", "min_size": "0.04", "max_size": "20000.0", "increment": "0.000001", "label": "ZEC/BTC" }, { "asset": "XMR", "currency": "USD", "min_size": "0.02", "max_size": "5000.0", "increment": "0.001", "label": "XMR/USD" }, { "asset": "XMR", "currency": "BTC", "min_size": "0.02", "max_size": "5000.0", "increment": "0.000001", "label": "XMR/BTC" }, { "asset": "DSH", "currency": "USD", "min_size": "0.02", "max_size": "5000.0", "increment": "0.001", "label": "DSH/USD" }, { "asset": "DSH", "currency": "BTC", "min_size": "0.02", "max_size": "5000.0", "increment": "0.000001", "label": "DSH/BTC" }, { "asset": "BTC", "currency": "EUR", "min_size": "0.0002", "max_size": "2000.0", "increment": "0.000001", "label": "BTC/EUR" }, { "asset": "BTC", "currency": "JPY", "min_size": "0.0002", "max_size": "2000.0", "increment": "0.000001", "label": "BTC/JPY" }, { "asset": "XRP", "currency": "USD", "min_size": "8.0", "max_size": "2000000.0", "increment": "0.00001", "label": "XRP/USD" }, { "asset": "XRP", "currency": "BTC", "min_size": "8.0", "max_size": "2000000.0", "increment": "0.00000001", "label": "XRP/BTC" }, { "asset": "IOT", "currency": "USD", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00001", "label": "IOT/USD" }, { "asset": "IOT", "currency": "BTC", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00000001", "label": "IOT/BTC" }, { "asset": "IOT", "currency": "ETH", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00000001", "label": "IOT/ETH" }, { "asset": "EOS", "currency": "USD", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0001", "label": "EOS/USD" }, { "asset": "EOS", "currency": "BTC", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/BTC" }, { "asset": "EOS", "currency": "ETH", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/ETH" }, { "asset": "SAN", "currency": "USD", "min_size": "14.0", "max_size": "200000.0", "increment": "0.00001", "label": "SAN/USD" }, { "asset": "SAN", "currency": "BTC", "min_size": "14.0", "max_size": "200000.0", "increment": "0.00000001", "label": "SAN/BTC" }, { "asset": "SAN", "currency": "ETH", "min_size": "14.0", "max_size": "200000.0", "increment": "0.00000001", "label": "SAN/ETH" }, { "asset": "OMG", "currency": "USD", "min_size": "0.6", "max_size": "100000.0", "increment": "0.0001", "label": "OMG/USD" }, { "asset": "OMG", "currency": "BTC", "min_size": "0.6", "max_size": "100000.0", "increment": "0.0000001", "label": "OMG/BTC" }, { "asset": "OMG", "currency": "ETH", "min_size": "0.6", "max_size": "100000.0", "increment": "0.0000001", "label": "OMG/ETH" }, { "asset": "NEO", "currency": "USD", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0001", "label": "NEO/USD" }, { "asset": "NEO", "currency": "BTC", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "NEO/BTC" }, { "asset": "NEO", "currency": "ETH", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "NEO/ETH" }, { "asset": "ETP", "currency": "USD", "min_size": "12.0", "max_size": "10000.0", "increment": "0.00001", "label": "ETP/USD" }, { "asset": "ETP", "currency": "BTC", "min_size": "12.0", "max_size": "10000.0", "increment": "0.00000001", "label": "ETP/BTC" }, { "asset": "ETP", "currency": "ETH", "min_size": "12.0", "max_size": "10000.0", "increment": "0.00000001", "label": "ETP/ETH" }, { "asset": "QTM", "currency": "USD", "min_size": "0.8", "max_size": "5000.0", "increment": "0.0001", "label": "QTM/USD" }, { "asset": "QTM", "currency": "BTC", "min_size": "0.8", "max_size": "5000.0", "increment": "0.0000001", "label": "QTM/BTC" }, { "asset": "EDO", "currency": "USD", "min_size": "4.0", "max_size": "50000.0", "increment": "0.00001", "label": "EDO/USD" }, { "asset": "EDO", "currency": "BTC", "min_size": "4.0", "max_size": "50000.0", "increment": "0.00000001", "label": "EDO/BTC" }, { "asset": "EDO", "currency": "ETH", "min_size": "4.0", "max_size": "50000.0", "increment": "0.00000001", "label": "EDO/ETH" }, { "asset": "BTG", "currency": "USD", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0001", "label": "BTG/USD" }, { "asset": "BTG", "currency": "BTC", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "BTG/BTC" }, { "asset": "DAT", "currency": "USD", "min_size": "48.0", "max_size": "250000.0", "increment": "0.000001", "label": "DAT/USD" }, { "asset": "DAT", "currency": "BTC", "min_size": "48.0", "max_size": "250000.0", "increment": "0.000000001", "label": "DAT/BTC" }, { "asset": "QSH", "currency": "USD", "min_size": "52.0", "max_size": "50000.0", "increment": "0.000001", "label": "QSH/USD" }, { "asset": "YYW", "currency": "USD", "min_size": "228.0", "max_size": "50000.0", "increment": "0.0000001", "label": "YYW/USD" }, { "asset": "GNT", "currency": "USD", "min_size": "20.0", "max_size": "250000.0", "increment": "0.00001", "label": "GNT/USD" }, { "asset": "SNT", "currency": "USD", "min_size": "82.0", "max_size": "500000.0", "increment": "0.000001", "label": "SNT/USD" }, { "asset": "IOT", "currency": "EUR", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00000001", "label": "IOT/EUR" }, { "asset": "BAT", "currency": "USD", "min_size": "8.0", "max_size": "200000.0", "increment": "0.00001", "label": "BAT/USD" }, { "asset": "BAT", "currency": "BTC", "min_size": "8.0", "max_size": "200000.0", "increment": "0.00000001", "label": "BAT/BTC" }, { "asset": "BAT", "currency": "ETH", "min_size": "8.0", "max_size": "200000.0", "increment": "0.00000001", "label": "BAT/ETH" }, { "asset": "MNA", "currency": "USD", "min_size": "24.0", "max_size": "200000.0", "increment": "0.00001", "label": "MNA/USD" }, { "asset": "MNA", "currency": "BTC", "min_size": "24.0", "max_size": "200000.0", "increment": "0.00000001", "label": "MNA/BTC" }, { "asset": "FUN", "currency": "USD", "min_size": "656.0", "max_size": "200000.0", "increment": "0.0000001", "label": "FUN/USD" }, { "asset": "ZRX", "currency": "USD", "min_size": "6.0", "max_size": "200000.0", "increment": "0.00001", "label": "ZRX/USD" }, { "asset": "ZRX", "currency": "BTC", "min_size": "6.0", "max_size": "200000.0", "increment": "0.00000001", "label": "ZRX/BTC" }, { "asset": "ZRX", "currency": "ETH", "min_size": "6.0", "max_size": "200000.0", "increment": "0.00000001", "label": "ZRX/ETH" }, { "asset": "TRX", "currency": "USD", "min_size": "74.0", "max_size": "1000000.0", "increment": "0.000001", "label": "TRX/USD" }, { "asset": "TRX", "currency": "BTC", "min_size": "74.0", "max_size": "1000000.0", "increment": "0.000000001", "label": "TRX/BTC" }, { "asset": "TRX", "currency": "ETH", "min_size": "74.0", "max_size": "1000000.0", "increment": "0.000000001", "label": "TRX/ETH" }, { "asset": "SNG", "currency": "USD", "min_size": "276.0", "max_size": "200000.0", "increment": "0.0000001", "label": "SNG/USD" }, { "asset": "REP", "currency": "USD", "min_size": "0.2", "max_size": "1000.0", "increment": "0.0001", "label": "REP/USD" }, { "asset": "REP", "currency": "BTC", "min_size": "0.2", "max_size": "1000.0", "increment": "0.0000001", "label": "REP/BTC" }, { "asset": "NEC", "currency": "USD", "min_size": "12.0", "max_size": "200000.0", "increment": "0.00001", "label": "NEC/USD" }, { "asset": "BTC", "currency": "GBP", "min_size": "0.0002", "max_size": "2000.0", "increment": "0.000001", "label": "BTC/GBP" }, { "asset": "ETH", "currency": "EUR", "min_size": "0.006", "max_size": "5000.0", "increment": "0.000001", "label": "ETH/EUR" }, { "asset": "ETH", "currency": "JPY", "min_size": "0.006", "max_size": "5000.0", "increment": "0.000001", "label": "ETH/JPY" }, { "asset": "ETH", "currency": "GBP", "min_size": "0.006", "max_size": "5000.0", "increment": "0.000001", "label": "ETH/GBP" }, { "asset": "NEO", "currency": "EUR", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "NEO/EUR" }, { "asset": "NEO", "currency": "JPY", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "NEO/JPY" }, { "asset": "NEO", "currency": "GBP", "min_size": "0.2", "max_size": "10000.0", "increment": "0.0000001", "label": "NEO/GBP" }, { "asset": "EOS", "currency": "EUR", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/EUR" }, { "asset": "EOS", "currency": "JPY", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/JPY" }, { "asset": "EOS", "currency": "GBP", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/GBP" }, { "asset": "IOT", "currency": "JPY", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00000001", "label": "IOT/JPY" }, { "asset": "IOT", "currency": "GBP", "min_size": "8.0", "max_size": "100000.0", "increment": "0.00000001", "label": "IOT/GBP" }, { "asset": "REQ", "currency": "USD", "min_size": "92.0", "max_size": "100000.0", "increment": "0.000001", "label": "REQ/USD" }, { "asset": "LRC", "currency": "USD", "min_size": "10.0", "max_size": "50000.0", "increment": "0.00001", "label": "LRC/USD" }, { "asset": "WAX", "currency": "USD", "min_size": "50.0", "max_size": "50000.0", "increment": "0.000001", "label": "WAX/USD" }, { "asset": "DAI", "currency": "USD", "min_size": "2.0", "max_size": "200000.0", "increment": "0.00001", "label": "DAI/USD" }, { "asset": "DAI", "currency": "BTC", "min_size": "2.0", "max_size": "200000.0", "increment": "0.00000001", "label": "DAI/BTC" }, { "asset": "DAI", "currency": "ETH", "min_size": "2.0", "max_size": "200000.0", "increment": "0.00000001", "label": "DAI/ETH" }, { "asset": "BFT", "currency": "USD", "min_size": "232.0", "max_size": "200000.0", "increment": "0.0000001", "label": "BFT/USD" }, { "asset": "ODE", "currency": "USD", "min_size": "92.0", "max_size": "200000.0", "increment": "0.000001", "label": "ODE/USD" }, { "asset": "ANT", "currency": "USD", "min_size": "0.6", "max_size": "10000.0", "increment": "0.0001", "label": "ANT/USD" }, { "asset": "ANT", "currency": "BTC", "min_size": "0.6", "max_size": "10000.0", "increment": "0.0000001", "label": "ANT/BTC" }, { "asset": "ANT", "currency": "ETH", "min_size": "0.6", "max_size": "10000.0", "increment": "0.0000001", "label": "ANT/ETH" }, { "asset": "STJ", "currency": "USD", "min_size": "4.0", "max_size": "30000.0", "increment": "0.00001", "label": "STJ/USD" }, { "asset": "XLM", "currency": "USD", "min_size": "28.0", "max_size": "1000000.0", "increment": "0.00001", "label": "XLM/USD" }, { "asset": "XLM", "currency": "BTC", "min_size": "28.0", "max_size": "1000000.0", "increment": "0.00000001", "label": "XLM/BTC" }, { "asset": "XLM", "currency": "ETH", "min_size": "28.0", "max_size": "1000000.0", "increment": "0.00000001", "label": "XLM/ETH" }, { "asset": "XVG", "currency": "USD", "min_size": "472.0", "max_size": "1500000.0", "increment": "0.0000001", "label": "XVG/USD" }, { "asset": "MKR", "currency": "USD", "min_size": "0.004", "max_size": "250.0", "increment": "0.001", "label": "MKR/USD" }, { "asset": "KNC", "currency": "USD", "min_size": "2.0", "max_size": "100000.0", "increment": "0.00001", "label": "KNC/USD" }, { "asset": "KNC", "currency": "BTC", "min_size": "2.0", "max_size": "20000.0", "increment": "0.00000001", "label": "KNC/BTC" }, { "asset": "POA", "currency": "USD", "min_size": "80.0", "max_size": "150000.0", "increment": "0.000001", "label": "POA/USD" }, { "asset": "LYM", "currency": "USD", "min_size": "904.0", "max_size": "400000.0", "increment": "0.0000001", "label": "LYM/USD" }, { "asset": "UTK", "currency": "USD", "min_size": "14.0", "max_size": "300000.0", "increment": "0.00001", "label": "UTK/USD" }, { "asset": "VEE", "currency": "USD", "min_size": "1332.0", "max_size": "5000000.0", "increment": "0.0000001", "label": "VEE/USD" }, { "asset": "ORS", "currency": "USD", "min_size": "180.0", "max_size": "500000.0", "increment": "0.0000001", "label": "ORS/USD" }, { "asset": "ZCN", "currency": "USD", "min_size": "8.0", "max_size": "50000.0", "increment": "0.00001", "label": "ZCN/USD" }, { "asset": "ESS", "currency": "USD", "min_size": "2046.0", "max_size": "20000000.0", "increment": "0.0000001", "label": "ESS/USD" }, { "asset": "IQX", "currency": "USD", "min_size": "986.0", "max_size": "100000000.0", "increment": "0.0000001", "label": "IQX/USD" }, { "asset": "ZIL", "currency": "USD", "min_size": "104.0", "max_size": "1500000.0", "increment": "0.000001", "label": "ZIL/USD" }, { "asset": "ZIL", "currency": "BTC", "min_size": "748.0", "max_size": "1500000.0", "increment": "0.0000000001", "label": "ZIL/BTC" }, { "asset": "BNT", "currency": "USD", "min_size": "2.0", "max_size": "20000.0", "increment": "0.00001", "label": "BNT/USD" }, { "asset": "XRA", "currency": "USD", "min_size": "204.0", "max_size": "500000.0", "increment": "0.0000001", "label": "XRA/USD" }, { "asset": "DGX", "currency": "USD", "min_size": "0.04", "max_size": "750.0", "increment": "0.001", "label": "DGX/USD" }, { "asset": "VET", "currency": "USD", "min_size": "156.0", "max_size": "5000000.0", "increment": "0.0000001", "label": "VET/USD" }, { "asset": "VET", "currency": "BTC", "min_size": "156.0", "max_size": "5000000.0", "increment": "0.0000000001", "label": "VET/BTC" }, { "asset": "GOT", "currency": "USD", "min_size": "32.0", "max_size": "50000.0", "increment": "0.000001", "label": "GOT/USD" }, { "asset": "GOT", "currency": "EUR", "min_size": "32.0", "max_size": "50000.0", "increment": "0.000000001", "label": "GOT/EUR" }, { "asset": "XTZ", "currency": "USD", "min_size": "1.0", "max_size": "100000.0", "increment": "0.0001", "label": "XTZ/USD" }, { "asset": "XTZ", "currency": "BTC", "min_size": "1.0", "max_size": "100000.0", "increment": "0.0000001", "label": "XTZ/BTC" }, { "asset": "TRX", "currency": "EUR", "min_size": "74.0", "max_size": "1000000.0", "increment": "0.000000001", "label": "TRX/EUR" }, { "asset": "YGG", "currency": "USD", "min_size": "12046.0", "max_size": "8000000.0", "increment": "0.0000001", "label": "YGG/USD" }, { "asset": "MLN", "currency": "USD", "min_size": "0.06", "max_size": "500000.0", "increment": "0.001", "label": "MLN/USD" }, { "asset": "OMN", "currency": "USD", "min_size": "0.6", "max_size": "20000.0", "increment": "0.0001", "label": "OMN/USD" }, { "asset": "OMN", "currency": "BTC", "min_size": "0.6", "max_size": "20000.0", "increment": "0.0000001", "label": "OMN/BTC" }, { "asset": "PNK", "currency": "USD", "min_size": "26.0", "max_size": "1000000.0", "increment": "0.00001", "label": "PNK/USD" }, { "asset": "PNK", "currency": "ETH", "min_size": "26.0", "max_size": "1000000.0", "increment": "0.00000001", "label": "PNK/ETH" }, { "asset": "DGB", "currency": "USD", "min_size": "76.0", "max_size": "2500000.0", "increment": "0.000001", "label": "DGB/USD" }, { "asset": "BSV", "currency": "USD", "min_size": "0.02", "max_size": "5000.0", "increment": "0.001", "label": "BSV/USD" }, { "asset": "BSV", "currency": "BTC", "min_size": "0.02", "max_size": "5000.0", "increment": "0.000001", "label": "BSV/BTC" }, { "asset": "ENJ", "currency": "USD", "min_size": "12.0", "max_size": "500000.0", "increment": "0.00001", "label": "ENJ/USD" }, { "asset": "RBT", "currency": "USD", "min_size": "0.0002", "max_size": "500.0", "increment": "0.001", "label": "RBT/USD" }, { "asset": "RBT", "currency": "BTC", "min_size": "0.0002", "max_size": "500.0", "increment": "0.000001", "label": "RBT/BTC" }, { "asset": "UST", "currency": "USD", "min_size": "2.0", "max_size": "5000000.0", "increment": "0.00001", "label": "UST/USD" }, { "asset": "EUT", "currency": "EUR", "min_size": "2.0", "max_size": "100000.0", "increment": "0.00000001", "label": "EUT/EUR" }, { "asset": "EUT", "currency": "USD", "min_size": "2.0", "max_size": "100000.0", "increment": "0.00001", "label": "EUT/USD" }, { "asset": "UDC", "currency": "USD", "min_size": "2.0", "max_size": "1000000.0", "increment": "0.00001", "label": "UDC/USD" }, { "asset": "TSD", "currency": "USD", "min_size": "2.0", "max_size": "1000000.0", "increment": "0.00001", "label": "TSD/USD" }, { "asset": "PAX", "currency": "USD", "min_size": "2.0", "max_size": "1000000.0", "increment": "0.00001", "label": "PAX/USD" }, { "asset": "PAS", "currency": "USD", "min_size": "1586.0", "max_size": "100000.0", "increment": "0.0000001", "label": "PAS/USD" }, { "asset": "VSY", "currency": "USD", "min_size": "100.0", "max_size": "250000.0", "increment": "0.000001", "label": "VSY/USD" }, { "asset": "VSY", "currency": "BTC", "min_size": "100.0", "max_size": "250000.0", "increment": "0.000000001", "label": "VSY/BTC" }, { "asset": "BTT", "currency": "USD", "min_size": "6036.0", "max_size": "100000000.0", "increment": "0.0000001", "label": "BTT/USD" }, { "asset": "BTC", "currency": "UST", "min_size": "0.0002", "max_size": "2000.0", "increment": "0.000001", "label": "BTC/UST" }, { "asset": "ETH", "currency": "UST", "min_size": "0.006", "max_size": "2000.0", "increment": "0.000001", "label": "ETH/UST" }, { "asset": "CLO", "currency": "USD", "min_size": "3696.0", "max_size": "1000000.0", "increment": "0.0000001", "label": "CLO/USD" }, { "asset": "LTC", "currency": "UST", "min_size": "0.04", "max_size": "2000.0", "increment": "0.000001", "label": "LTC/UST" }, { "asset": "EOS", "currency": "UST", "min_size": "0.8", "max_size": "50000.0", "increment": "0.0000001", "label": "EOS/UST" }, { "asset": "GNO", "currency": "USD", "min_size": "0.04", "max_size": "1000.0", "increment": "0.001", "label": "GNO/USD" }, { "asset": "ATO", "currency": "USD", "min_size": "0.4", "max_size": "100000.0", "increment": "0.0001", "label": "ATO/USD" }, { "asset": "ATO", "currency": "BTC", "min_size": "0.4", "max_size": "100000.0", "increment": "0.0000001", "label": "ATO/BTC" }, { "asset": "ATO", "currency": "ETH", "min_size": "0.4", "max_size": "100000.0", "increment": "0.0000001", "label": "ATO/ETH" }, { "asset": "WBT", "currency": "USD", "min_size": "0.0002", "max_size": "10.0", "increment": "0.001", "label": "WBT/USD" }, { "asset": "XCH", "currency": "USD", "min_size": "2.0", "max_size": "30000.0", "increment": "0.00001", "label": "XCH/USD" }, { "asset": "EUS", "currency": "USD", "min_size": "2.0", "max_size": "250000.0", "increment": "0.00001", "label": "EUS/USD" }, { "asset": "LEO", "currency": "USD", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00001", "label": "LEO/USD" }, { "asset": "LEO", "currency": "BTC", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "LEO/BTC" }, { "asset": "LEO", "currency": "UST", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "LEO/UST" }, { "asset": "LEO", "currency": "EOS", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "LEO/EOS" }, { "asset": "LEO", "currency": "ETH", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "LEO/ETH" }, { "asset": "ZBT", "currency": "USD", "min_size": "6.0", "max_size": "25000.0", "increment": "0.00001", "label": "ZBT/USD" }, { "asset": "USK", "currency": "USD", "min_size": "2.0", "max_size": "250000.0", "increment": "0.00001", "label": "USK/USD" }, { "asset": "GTX", "currency": "USD", "min_size": "4.0", "max_size": "10000.0", "increment": "0.00001", "label": "GTX/USD" }, { "asset": "KAN", "currency": "USD", "min_size": "430.0", "max_size": "500000.0", "increment": "0.0000001", "label": "KAN/USD" }, { "asset": "GTX", "currency": "UST", "min_size": "4.0", "max_size": "10000.0", "increment": "0.00000001", "label": "GTX/UST" }, { "asset": "KAN", "currency": "UST", "min_size": "430.0", "max_size": "500000.0", "increment": "0.0000000001", "label": "KAN/UST" }, { "asset": "AMP", "currency": "USD", "min_size": "2.0", "max_size": "25000.0", "increment": "0.00001", "label": "AMP/USD" }, { "asset": "ALG", "currency": "USD", "min_size": "6.0", "max_size": "150000.0", "increment": "0.00001", "label": "ALG/USD" }, { "asset": "ALG", "currency": "BTC", "min_size": "6.0", "max_size": "150000.0", "increment": "0.00000001", "label": "ALG/BTC" }, { "asset": "ALG", "currency": "UST", "min_size": "6.0", "max_size": "150000.0", "increment": "0.00000001", "label": "ALG/UST" }, { "asset": "BTC", "currency": "XCH", "min_size": "0.0002", "max_size": "25000.0", "increment": "0.000001", "label": "BTC/XCH" }, { "asset": "AMP", "currency": "UST", "min_size": "2.0", "max_size": "25000.0", "increment": "0.00000001", "label": "AMP/UST" }, { "asset": "DUS", "currency": "K:U", "min_size": "38.0", "max_size": "100000.0", "increment": "0.000000001", "label": "DUS/K:U" }, { "asset": "DUS", "currency": "K:B", "min_size": "38.0", "max_size": "100000.0", "increment": "0.000000001", "label": "DUS/K:B" }, { "asset": "UOS", "currency": "USD", "min_size": "16.0", "max_size": "400000.0", "increment": "0.00001", "label": "UOS/USD" }, { "asset": "UOS", "currency": "BTC", "min_size": "16.0", "max_size": "400000.0", "increment": "0.00000001", "label": "UOS/BTC" }, { "asset": "RRB", "currency": "USD", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00001", "label": "RRB/USD" }, { "asset": "RRB", "currency": "UST", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "RRB/UST" }, { "asset": "AMP", "currency": "BTC", "min_size": "2.0", "max_size": "25000.0", "increment": "0.00000001", "label": "AMP/BTC" }, { "asset": "FTT", "currency": "USD", "min_size": "0.6", "max_size": "50000.0", "increment": "0.0001", "label": "FTT/USD" }, { "asset": "FTT", "currency": "UST", "min_size": "0.6", "max_size": "50000.0", "increment": "0.0000001", "label": "FTT/UST" }, { "asset": "PAX", "currency": "UST", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "PAX/UST" }, { "asset": "UDC", "currency": "UST", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "UDC/UST" }, { "asset": "TSD", "currency": "UST", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "TSD/UST" }, { "asset": "BTC", "currency": ":CN", "min_size": "0.0002", "max_size": "5000.0", "increment": "0.000001", "label": "BTC/:CN" }, { "asset": "UST", "currency": ":CN", "min_size": "2.0", "max_size": "50000.0", "increment": "0.00000001", "label": "UST/:CN" }, { "asset": "CNH", "currency": ":CN", "min_size": "2.0", "max_size": "500000.0", "increment": "0.00000001", "label": "CNH/:CN" }, { "asset": "CHZ", "currency": "USD", "min_size": "128.0", "max_size": "250000.0", "increment": "0.000001", "label": "CHZ/USD" }, { "asset": "CHZ", "currency": "UST", "min_size": "128.0", "max_size": "250000.0", "increment": "0.000000001", "label": "CHZ/UST" }, { "asset": "XAU", "currency": "T:U", "min_size": "0.002", "max_size": "400.0", "increment": "0.000001", "label": "XAU/T:U" }, { "asset": "XAU", "currency": "T:B", "min_size": "0.002", "max_size": "400.0", "increment": "0.000001", "label": "XAU/T:B" }, { "asset": "XAU", "currency": "T:U", "min_size": "0.002", "max_size": "400.0", "increment": "0.000001", "label": "XAU/T:U" }, { "asset": "RIN", "currency": "GX:", "min_size": "18.0", "max_size": "100000.0", "increment": "0.00000001", "label": "RIN/GX:" }, { "asset": "BTS", "currency": "E:U", "min_size": "0.4", "max_size": "10000.0", "increment": "0.0000001", "label": "BTS/E:U" }, { "asset": "TES", "currency": "TBT", "min_size": "0.0002", "max_size": "100.0", "increment": "0.000001", "label": "TES/TBT" }, { "asset": "TES", "currency": "TBT", "min_size": "0.0002", "max_size": "100.0", "increment": "0.000001", "label": "TES/TBT" }, { "asset": "AAA", "currency": "BBB", "min_size": "2.0", "max_size": "100.0", "increment": "0.00000001", "label": "AAA/BBB" }, { "asset": "DOG", "currency": "USD", "min_size": "0.0004", "max_size": "1000.0", "increment": "0.001", "label": "DOG/USD" }, { "asset": "DOG", "currency": "BTC", "min_size": "0.0004", "max_size": "1000.0", "increment": "0.000001", "label": "DOG/BTC" }, { "asset": "DOG", "currency": "UST", "min_size": "0.0004", "max_size": "1000.0", "increment": "0.000001", "label": "DOG/UST" }, { "asset": "DOT", "currency": "USD", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0001", "label": "DOT/USD" }, { "asset": "ADA", "currency": "USD", "min_size": "10.0", "max_size": "250000.0", "increment": "0.00001", "label": "ADA/USD" }, { "asset": "ADA", "currency": "BTC", "min_size": "10.0", "max_size": "250000.0", "increment": "0.00000001", "label": "ADA/BTC" }, { "asset": "ADA", "currency": "UST", "min_size": "10.0", "max_size": "250000.0", "increment": "0.00000001", "label": "ADA/UST" }, { "asset": "FET", "currency": "USD", "min_size": "18.0", "max_size": "250000.0", "increment": "0.00001", "label": "FET/USD" }, { "asset": "FET", "currency": "UST", "min_size": "18.0", "max_size": "250000.0", "increment": "0.00000001", "label": "FET/UST" }, { "asset": "DOT", "currency": "UST", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "DOT/UST" }, { "asset": "LIN", "currency": "K:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "LIN/K:U" }, { "asset": "LIN", "currency": "K:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "LIN/K:U" }, { "asset": "COM", "currency": "P:U", "min_size": "0.008", "max_size": "5000.0", "increment": "0.000001", "label": "COM/P:U" }, { "asset": "COM", "currency": "P:U", "min_size": "0.008", "max_size": "5000.0", "increment": "0.000001", "label": "COM/P:U" }, { "asset": "KSM", "currency": "USD", "min_size": "0.04", "max_size": "5000.0", "increment": "0.001", "label": "KSM/USD" }, { "asset": "KSM", "currency": "UST", "min_size": "0.04", "max_size": "5000.0", "increment": "0.000001", "label": "KSM/UST" }, { "asset": "EGL", "currency": "D:U", "min_size": "0.2", "max_size": "5000.0", "increment": "0.0000001", "label": "EGL/D:U" }, { "asset": "EGL", "currency": "D:U", "min_size": "0.2", "max_size": "5000.0", "increment": "0.0000001", "label": "EGL/D:U" }, { "asset": "UNI", "currency": "USD", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0001", "label": "UNI/USD" }, { "asset": "UNI", "currency": "UST", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "UNI/UST" }, { "asset": "BAN", "currency": "D:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "BAN/D:U" }, { "asset": "BAN", "currency": "D:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "BAN/D:U" }, { "asset": "AVA", "currency": "X:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "AVA/X:U" }, { "asset": "AVA", "currency": "X:U", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "AVA/X:U" }, { "asset": "SNX", "currency": "USD", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0001", "label": "SNX/USD" }, { "asset": "SNX", "currency": "UST", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "SNX/UST" }, { "asset": "YFI", "currency": "USD", "min_size": "0.0001", "max_size": "100.0", "increment": "0.001", "label": "YFI/USD" }, { "asset": "YFI", "currency": "UST", "min_size": "0.0001", "max_size": "100.0", "increment": "0.000001", "label": "YFI/UST" }, { "asset": "BAL", "currency": "USD", "min_size": "0.06", "max_size": "10000.0", "increment": "0.001", "label": "BAL/USD" }, { "asset": "BAL", "currency": "UST", "min_size": "0.06", "max_size": "10000.0", "increment": "0.000001", "label": "BAL/UST" }, { "asset": "EOS", "currency": "DT:", "min_size": "0.001", "max_size": "25000.0", "increment": "0.000001", "label": "EOS/DT:" }, { "asset": "EOS", "currency": "DT:", "min_size": "0.001", "max_size": "25000.0", "increment": "0.000001", "label": "EOS/DT:" }, { "asset": "NUT", "currency": "USD", "min_size": "0.001", "max_size": "1000.0", "increment": "0.001", "label": "NUT/USD" }, { "asset": "DAP", "currency": "P:U", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "DAP/P:U" }, { "asset": "DAP", "currency": "P:U", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "DAP/P:U" }, { "asset": "FIL", "currency": "USD", "min_size": "0.001", "max_size": "10000.0", "increment": "0.001", "label": "FIL/USD" }, { "asset": "FIL", "currency": "UST", "min_size": "0.001", "max_size": "10000.0", "increment": "0.000001", "label": "FIL/UST" }, { "asset": "JST", "currency": "USD", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.001", "label": "JST/USD" }, { "asset": "JST", "currency": "BTC", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "JST/BTC" }, { "asset": "JST", "currency": "UST", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "JST/UST" }, { "asset": "IQX", "currency": "UST", "min_size": "986.0", "max_size": "100000000.0", "increment": "0.0000000001", "label": "IQX/UST" }, { "asset": "HEZ", "currency": "USD", "min_size": "0.001", "max_size": "10000.0", "increment": "0.001", "label": "HEZ/USD" }, { "asset": "HEZ", "currency": "UST", "min_size": "0.001", "max_size": "10000.0", "increment": "0.000001", "label": "HEZ/UST" }, { "asset": "BCH", "currency": "ABC", "min_size": "0.001", "max_size": "1000.0", "increment": "0.000001", "label": "BCH/ABC" }, { "asset": "BCH", "currency": "N:U", "min_size": "0.001", "max_size": "1000.0", "increment": "0.000001", "label": "BCH/N:U" }, { "asset": "XDC", "currency": "USD", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.001", "label": "XDC/USD" }, { "asset": "XDC", "currency": "UST", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "XDC/UST" }, { "asset": "PLU", "currency": "USD", "min_size": "0.001", "max_size": "10000.0", "increment": "0.001", "label": "PLU/USD" }, { "asset": "SUN", "currency": "USD", "min_size": "0.001", "max_size": "10000.0", "increment": "0.001", "label": "SUN/USD" }, { "asset": "SUN", "currency": "UST", "min_size": "0.001", "max_size": "10000.0", "increment": "0.000001", "label": "SUN/UST" }, { "asset": "UOP", "currency": "USD", "min_size": "0.001", "max_size": "100000.0", "increment": "0.001", "label": "UOP/USD" }, { "asset": "UOP", "currency": "UST", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "UOP/UST" }, { "asset": "EUT", "currency": "UST", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "EUT/UST" }, { "asset": "XMR", "currency": "UST", "min_size": "0.001", "max_size": "5000.0", "increment": "0.000001", "label": "XMR/UST" }, { "asset": "XRP", "currency": "UST", "min_size": "0.001", "max_size": "2000000.0", "increment": "0.000001", "label": "XRP/UST" }, { "asset": "B21", "currency": "X:U", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "B21/X:U" }, { "asset": "B21", "currency": "X:U", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "B21/X:U" }, { "asset": "SUS", "currency": "HI:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "SUS/HI:" }, { "asset": "SUS", "currency": "HI:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "SUS/HI:" }, { "asset": "XSN", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "XSN/USD" }, { "asset": "EXR", "currency": "D:U", "min_size": "0.001", "max_size": "500000.0", "increment": "0.000001", "label": "EXR/D:U" }, { "asset": "EXR", "currency": "D:B", "min_size": "0.001", "max_size": "500000.0", "increment": "0.000001", "label": "EXR/D:B" }, { "asset": "DOT", "currency": "BTC", "min_size": "0.2", "max_size": "50000.0", "increment": "0.0000001", "label": "DOT/BTC" }, { "asset": "ETH", "currency": "2X:", "min_size": "0.001", "max_size": "2000.0", "increment": "0.000001", "label": "ETH/2X:" }, { "asset": "ETH", "currency": "2X:", "min_size": "0.001", "max_size": "2000.0", "increment": "0.000001", "label": "ETH/2X:" }, { "asset": "ETH", "currency": "2X:", "min_size": "0.001", "max_size": "2000.0", "increment": "0.000001", "label": "ETH/2X:" }, { "asset": "AAV", "currency": "E:U", "min_size": "0.001", "max_size": "5000.0", "increment": "0.000001", "label": "AAV/E:U" }, { "asset": "AAV", "currency": "E:U", "min_size": "0.001", "max_size": "5000.0", "increment": "0.000001", "label": "AAV/E:U" }, { "asset": "XLM", "currency": "UST", "min_size": "10.0", "max_size": "1000000.0", "increment": "0.00000001", "label": "XLM/UST" }, { "asset": "EUS", "currency": "BTC", "min_size": "2.0", "max_size": "250000.0", "increment": "0.00000001", "label": "EUS/BTC" }, { "asset": "CTK", "currency": "USD", "min_size": "0.001", "max_size": "5000.0", "increment": "0.001", "label": "CTK/USD" }, { "asset": "CTK", "currency": "UST", "min_size": "0.001", "max_size": "5000.0", "increment": "0.000001", "label": "CTK/UST" }, { "asset": "SOL", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "SOL/USD" }, { "asset": "SOL", "currency": "UST", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "SOL/UST" }, { "asset": "BES", "currency": "T:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "BES/T:U" }, { "asset": "ALB", "currency": "T:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "ALB/T:U" }, { "asset": "ALB", "currency": "T:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "ALB/T:U" }, { "asset": "CEL", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "CEL/USD" }, { "asset": "CEL", "currency": "UST", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "CEL/UST" }, { "asset": "SUK", "currency": "U:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "SUK/U:U" }, { "asset": "SUK", "currency": "U:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "SUK/U:U" }, { "asset": "BMI", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "BMI/USD" }, { "asset": "BMI", "currency": "UST", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "BMI/UST" }, { "asset": "MOB", "currency": "USD", "min_size": "0.001", "max_size": "10000.0", "increment": "0.001", "label": "MOB/USD" }, { "asset": "MOB", "currency": "UST", "min_size": "0.001", "max_size": "10000.0", "increment": "0.000001", "label": "MOB/UST" }, { "asset": "NEA", "currency": "R:U", "min_size": "0.001", "max_size": "25000.0", "increment": "0.000001", "label": "NEA/R:U" }, { "asset": "NEA", "currency": "R:U", "min_size": "0.001", "max_size": "25000.0", "increment": "0.000001", "label": "NEA/R:U" }, { "asset": "BOS", "currency": "ON:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "BOS/ON:" }, { "asset": "BOS", "currency": "ON:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "BOS/ON:" }, { "asset": "LUN", "currency": "A:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "LUN/A:U" }, { "asset": "LUN", "currency": "A:U", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "LUN/A:U" }, { "asset": "ICE", "currency": "USD", "min_size": "0.001", "max_size": "25000.0", "increment": "0.001", "label": "ICE/USD" }, { "asset": "DOG", "currency": "E:U", "min_size": "0.001", "max_size": "1500000.0", "increment": "0.000001", "label": "DOG/E:U" }, { "asset": "DOG", "currency": "E:U", "min_size": "0.001", "max_size": "1500000.0", "increment": "0.000001", "label": "DOG/E:U" }, { "asset": "OXY", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "OXY/USD" }, { "asset": "OXY", "currency": "UST", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "OXY/UST" }, { "asset": "1IN", "currency": "CH:", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "1IN/CH:" }, { "asset": "1IN", "currency": "CH:", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "1IN/CH:" }, { "asset": "IDX", "currency": "USD", "min_size": "0.001", "max_size": "100000.0", "increment": "0.001", "label": "IDX/USD" }, { "asset": "FOR", "currency": "TH:", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "FOR/TH:" }, { "asset": "FOR", "currency": "TH:", "min_size": "0.001", "max_size": "100000.0", "increment": "0.000001", "label": "FOR/TH:" }, { "asset": "IDX", "currency": "UST", "min_size": "0.001", "max_size": "2000.0", "increment": "0.000001", "label": "IDX/UST" }, { "asset": "CHE", "currency": "X:U", "min_size": "0.001", "max_size": "1000000.0", "increment": "0.000001", "label": "CHE/X:U" }, { "asset": "QTF", "currency": "USD", "min_size": "0.001", "max_size": "50000.0", "increment": "0.001", "label": "QTF/USD" }, { "asset": "QTF", "currency": "BTC", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "QTF/BTC" }, { "asset": "OCE", "currency": "AN:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "OCE/AN:" }, { "asset": "OCE", "currency": "AN:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "OCE/AN:" }, { "asset": "PLA", "currency": "NET", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "PLA/NET" }, { "asset": "PLA", "currency": "NET", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "PLA/NET" }, { "asset": "BTC", "currency": "F0:", "min_size": "0.0002", "max_size": "100.0", "increment": "0.000001", "label": "BTC/F0:" }, { "asset": "ETH", "currency": "F0:", "min_size": "0.006", "max_size": "1000.0", "increment": "0.000001", "label": "ETH/F0:" }, { "asset": "XAU", "currency": "TF0", "min_size": "0.002", "max_size": "400.0", "increment": "0.000001", "label": "XAU/TF0" }, { "asset": "BTC", "currency": "DOM", "min_size": "0.008", "max_size": "5000.0", "increment": "0.000001", "label": "BTC/DOM" }, { "asset": "TES", "currency": "TBT", "min_size": "0.0002", "max_size": "1000.0", "increment": "0.000001", "label": "TES/TBT" }, { "asset": "AMP", "currency": "F0:", "min_size": "2.0", "max_size": "100000.0", "increment": "0.00000001", "label": "AMP/F0:" }, { "asset": "EUR", "currency": "F0:", "min_size": "0.8", "max_size": "250000.0", "increment": "0.0000001", "label": "EUR/F0:" }, { "asset": "GBP", "currency": "F0:", "min_size": "0.8", "max_size": "250000.0", "increment": "0.0000001", "label": "GBP/F0:" }, { "asset": "JPY", "currency": "F0:", "min_size": "106.0", "max_size": "10000000.0", "increment": "0.000000001", "label": "JPY/F0:" }, { "asset": "EUR", "currency": "OPE", "min_size": "0.0006", "max_size": "1000.0", "increment": "0.000001", "label": "EUR/OPE" }, { "asset": "GER", "currency": "MAN", "min_size": "0.0002", "max_size": "1000.0", "increment": "0.000001", "label": "GER/MAN" }, { "asset": "EOS", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "EOS/F0:" }, { "asset": "LTC", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "LTC/F0:" }, { "asset": "DOT", "currency": "F0:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "DOT/F0:" }, { "asset": "XAG", "currency": "F0:", "min_size": "0.001", "max_size": "10000.0", "increment": "0.000001", "label": "XAG/F0:" }, { "asset": "IOT", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "IOT/F0:" }, { "asset": "LIN", "currency": "KF0", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "LIN/KF0" }, { "asset": "UNI", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "UNI/F0:" }, { "asset": "ETH", "currency": "F0:", "min_size": "0.001", "max_size": "100.0", "increment": "0.000001", "label": "ETH/F0:" }, { "asset": "ADA", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "ADA/F0:" }, { "asset": "XLM", "currency": "F0:", "min_size": "0.001", "max_size": "250000.0", "increment": "0.000001", "label": "XLM/F0:" }, { "asset": "DOT", "currency": "F0:", "min_size": "0.001", "max_size": "50000.0", "increment": "0.000001", "label": "DOT/F0:" }, { "asset": "LTC", "currency": "F0:", "min_size": "0.001", "max_size": "7500.0", "increment": "0.000001", "label": "LTC/F0:" }, { "asset": "XAU", "currency": "TF0", "min_size": "0.001", "max_size": "500.0", "increment": "0.000001", "label": "XAU/TF0" }, { "asset": "DOG", "currency": "EF0", "min_size": "0.001", "max_size": "500000.0", "increment": "0.000001", "label": "DOG/EF0" } ] ================================================ FILE: extensions/exchanges/bitfinex/update-products.sh ================================================ #!/usr/bin/env node var request = require('micro-request') request('https://api.bitfinex.com/v1/symbols_details', {headers: {'User-Agent': 'zenbot/4'}}, function (err, resp, body) { if (err) throw err if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body console.error(err) process.exit(1) } var products = [] body.forEach(function (product) { var min_size = parseFloat(product.minimum_order_size) var prec = 0 if (min_size > 130 ) { prec = 4 } else if (min_size > 30) { prec = 3 } else if (min_size > 1) { prec = 2 } else if (min_size > 0.1) { prec = 1 } var increment = '0.' + '0'.repeat(prec + product.price_precision - (product.pair.substring(3, 6).toUpperCase() == 'USD' ? 3 : 0)) + '1' products.push({ // id: product.pair, asset: product.pair.substring(0, 3).toUpperCase(), currency: product.pair.substring(3, 6).toUpperCase(), min_size: product.minimum_order_size, max_size: product.maximum_order_size, increment: increment, label: product.pair.substring(0, 3).toUpperCase() + '/' + product.pair.substring(3, 6).toUpperCase() }) }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/bitstamp/exchange.js ================================================ var Bitstamp = require('bitstamp') , path = require('path') , WebSocket = require('ws') // eslint-disable-next-line no-unused-vars , n = require('numbro') , _ = require('lodash') const { GridFSBucket } = require('mongodb') var args = process.argv const restAPIURL = 'www.bitstamp.net' const wsURL = 'wss://ws.bitstamp.net' var wsOpts = { pairOk: false, currencyPair: 'btcusd', trades: { evType: 'trade', channel: 'live_trades' }, quotes: { evType: 'data', channel: 'order_book' } } // The use of bitstamp-ws requires that // Knowledge of the asset/currency pair // before the first call for a trade // As zenbot dont returns the currency pair // before the first trade is requested // it has been neccessary to get it from // the command line arguments parsePairDataFromArgs(args); function parsePairDataFromArgs(argsData) { for (const value of argsData) { if (value.toLowerCase().match(/bitstamp/)) { var p = value.split('.')[1] var prod = p.split('-')[0] + p.split('-')[1] var pair = prod.toLowerCase() if (!wsOpts.pairOk) { wsOpts.trades.channel = 'live_trades_' + pair wsOpts.quotes.channel = 'order_book_' + pair wsOpts.currencyPair = pair wsOpts.pairOk = true break } } } }; function joinProduct(product_id) { return product_id.split('-')[0] + product_id.split('-')[1] } module.exports = function bitstamp(conf) { function authedClient() { if (conf.bitstamp.key && conf.bitstamp.key !== 'YOUR-API-KEY') { return new Bitstamp(conf.bitstamp.key, conf.bitstamp.secret, conf.bitstamp.client_id, 5000, restAPIURL) } throw new Error('\nPlease configure your Bitstamp credentials in ' + path.resolve(__dirname, 'conf.js')) } //----------------------------------------------------- // The websocket functions // var Bitstamp_WS = function (confSelector) { // if pair data was not received from cli args, parse it from the selector if (!wsOpts.pairOk) { parsePairDataFromArgs([confSelector]) } // fetch initial order book from REST var client = new Bitstamp(null, null, null, 5000, restAPIURL) client.order_book(wsOpts.currencyPair, function (err, data) { wsquotes = { bid: data.bids[0][0], ask: data.asks[0][0] } }); this.client = new WebSocket(wsURL) // bitstamp publishes all data over just 2 channels // make sure we only subscribe to each channel once this.bound = { trade: false, data: false } // subscribe on open this.client.on('open', function open() { this.subscribe() }.bind(this)) } Bitstamp.prototype.tradeDaily = function (direction, market, amount, price, callback) { this._post(market, direction, callback, { amount: amount, price: price, daily_order: true }) } Bitstamp.prototype.tradeMarket = function (direction, market, amount, callback) { this._post(market, direction + '/market', callback, { amount: amount, }) } var util = require('util') var EventEmitter = require('events').EventEmitter util.inherits(Bitstamp_WS, EventEmitter) Bitstamp_WS.prototype.createSubscribeMessage = function (chanName) { return JSON.stringify({ "event": "bts:subscribe", "data": { "channel": chanName } }) } Bitstamp_WS.prototype.bindEvent = function (eventBroadcasts) { this.client.on('message', function incoming(data) { var parsedData = JSON.parse(data); Object.keys(eventBroadcasts).forEach(function (eventName) { if (parsedData.event === eventName) { var broadcastFunction = eventBroadcasts[eventName] broadcastFunction(parsedData.data); } }) }); } Bitstamp_WS.prototype.subscribe = function () { if (wsOpts.pairOk) { var eventFunctions = {}; this.client.send(this.createSubscribeMessage(wsOpts.trades.channel)); eventFunctions[wsOpts.trades.evType] = this.broadcast(wsOpts.trades.evType) this.client.send(this.createSubscribeMessage(wsOpts.quotes.channel)); eventFunctions[wsOpts.quotes.evType] = this.broadcast(wsOpts.quotes.evType) this.bindEvent(eventFunctions) } } Bitstamp_WS.prototype.broadcast = function (name) { if (this.bound[name]) return function noop() { } this.bound[name] = true return function (e) { this.emit(name, e) }.bind(this) } // Placeholders var wsquotes = {} var wstrades = [] var bistampWS = new Bitstamp_WS(conf.selector) bistampWS.on('data', function (data) { wsquotes = { bid: data.bids[0][0], ask: data.asks[0][0] } }) bistampWS.on('trade', function (data) { wstrades.push({ trade_id: data.id, time: Number(data.timestamp) * 1000, size: data.amount, price: data.price, side: data.type === 0 ? 'buy' : 'sell' }) }) //----------------------------------------------------- function statusErr(err, body) { if (typeof body === 'undefined') { var ret = {} var res = err.toString().split(':', 2) ret.status = res[1] return new Error(ret.status) } else { if (body.error) { return new Error('\nError: ' + body.error) } else { return body } } } function retry(method, wait, args) { if (method !== 'getTrades') { console.error(('\nBitstamp API is not answering! unable to call ' + method + ', retrying in ' + wait + 's').red) } setTimeout(function () { exchange[method].apply(exchange, args) }, wait * 1000) } var lastBalance = { asset: 0, currency: 0 } var orders = {} var exchange = { name: 'bitstamp', historyScan: false, makerFee: 0.50, takerFee: 0.50, getProducts: function () { return require('./products.json') }, //----------------------------------------------------- // Public API functions // getQuote() and getTrades() are using Bitstamp websockets // The data is not done by calling the interface function, // but rather pulled from the "wstrades" and "wsquotes" JSOM objects // Those objects are populated by the websockets event handlers getTrades: function (opts, cb) { var wait = 2 // Seconds var func_args = [].slice.call(arguments) if (wstrades.length === 0) return retry('getTrades', wait, func_args) var trades = wstrades.splice(0, wstrades.length) cb(null, trades) }, getQuote: function (opts, cb) { var wait = 2 // Seconds var func_args = [].slice.call(arguments) if (_.isEmpty(wsquotes)) return retry('getQuote', wait, func_args) cb(null, wsquotes) }, //----------------------------------------------------- // Private (authenticated) functions // getBalance: function (opts, cb) { var wait = 10 var func_args = [].slice.call(arguments) var client = authedClient() client.balance(null, function (err, body) { body = statusErr(err, body) if (body.status === 'error') { return retry('getBalance', wait, func_args) } var balance = { asset: '0', asset_hold: '0', currency: '0', currency_hold: '0' } // Dirty hack to avoid engine.js bailing out when balance has 0 value // The added amount is small enough to not have any significant effect balance.currency = n(body[opts.currency.toLowerCase() + '_balance']) + 0.000001 balance.asset = n(body[opts.asset.toLowerCase() + '_balance']) + 0.000001 balance.currency_hold = n(body[opts.currency.toLowerCase() + '_reserved']) + 0.000001 balance.asset_hold = n(body[opts.asset.toLowerCase() + '_reserved']) + 0.000001 if (typeof balance.asset == undefined || typeof balance.currency == undefined) { console.log('Communication delay, fallback to previous balance') balance = lastBalance } else { lastBalance = balance } cb(null, balance) }) }, cancelOrder: function (opts, cb) { var wait = 2; var func_args = [].slice.call(arguments) var client = authedClient() client.cancel_order(opts.order_id, function (err, body) { body = statusErr(err, body) if (body.status === 'error') { return retry('cancelOrder', wait, func_args) } cb() }) }, trade: function (type, opts, cb) { var client = authedClient() var currencyPair = joinProduct(opts.product_id).toLowerCase() if (typeof opts.order_type === 'undefined') { opts.order_type = 'maker' } // Bitstamp has no "post only" trade type opts.post_only = false if (opts.order_type === 'maker') { client.tradeDaily(type, currencyPair, opts.size, opts.price, function (err, body) { body = statusErr(err, body) if (body.status === 'error') { var order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } else { // Statuses: // 'In Queue', 'Open', 'Finished' body.status = 'done' } if (body.datetime) body.done_at = body.created_at = body.datetime orders['~' + body.id] = body cb(null, body) }) } else { // order_type === taker client.tradeMarket(type, currencyPair, opts.size, function (err, body) { body = statusErr(err, body) if (body.status === 'error') { var order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } else { body.status = 'done' } orders['~' + body.id] = body cb(null, body) }) } }, buy: function (opts, cb) { exchange.trade('buy', opts, cb) }, sell: function (opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function (opts, cb) { var client = authedClient() client.order_status(opts.order_id, function (err, body) { body = statusErr(err, body) if (body.status === 'error') { body = orders['~' + opts.order_id] body.status = 'done' body.done_reason = 'canceled' } else if (body.status === 'Finished') body.status = 'done' if (body.status === 'done') { if (body.transactions && body.transactions[0].datetime) body.done_at = body.transactions[0].datetime } cb(null, body) }) }, // return the property used for range querying. getCursor: function (trade) { return trade.trade_id } } return exchange } ================================================ FILE: extensions/exchanges/bitstamp/products.json ================================================ [ { "id": "BTCUSD", "asset": "BTC", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BTC/USD" }, { "id": "BTCEUR", "asset": "BTC", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BTC/EUR" }, { "id": "BTCGBP", "asset": "BTC", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BTC/GBP" }, { "id": "BTCPAX", "asset": "BTC", "currency": "PAX", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BTC/PAX" }, { "id": "BTCUSDC", "asset": "BTC", "currency": "USDC", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BTC/USDC" }, { "id": "GBPUSD", "asset": "GBP", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "GBP/USD" }, { "id": "GBPEUR", "asset": "GBP", "currency": "EUR", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "GBP/EUR" }, { "id": "EURUSD", "asset": "EUR", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "EUR/USD" }, { "id": "ETHUSD", "asset": "ETH", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "ETH/USD" }, { "id": "ETHEUR", "asset": "ETH", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "ETH/EUR" }, { "id": "ETHBTC", "asset": "ETH", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "ETH/BTC" }, { "id": "ETHGBP", "asset": "ETH", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "ETH/GBP" }, { "id": "ETHPAX", "asset": "ETH", "currency": "PAX", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "ETH/PAX" }, { "id": "ETHUSDC", "asset": "ETH", "currency": "USDC", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "ETH/USDC" }, { "id": "XRPUSD", "asset": "XRP", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XRP/USD" }, { "id": "XRPEUR", "asset": "XRP", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XRP/EUR" }, { "id": "XRPBTC", "asset": "XRP", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "XRP/BTC" }, { "id": "XRPGBP", "asset": "XRP", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XRP/GBP" }, { "id": "XRPPAX", "asset": "XRP", "currency": "PAX", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XRP/PAX" }, { "id": "UNIUSD", "asset": "UNI", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "UNI/USD" }, { "id": "UNIEUR", "asset": "UNI", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "UNI/EUR" }, { "id": "UNIBTC", "asset": "UNI", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "UNI/BTC" }, { "id": "LTCUSD", "asset": "LTC", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LTC/USD" }, { "id": "LTCEUR", "asset": "LTC", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LTC/EUR" }, { "id": "LTCBTC", "asset": "LTC", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "LTC/BTC" }, { "id": "LTCGBP", "asset": "LTC", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LTC/GBP" }, { "id": "LINKUSD", "asset": "LINK", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LINK/USD" }, { "id": "LINKEUR", "asset": "LINK", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LINK/EUR" }, { "id": "LINKGBP", "asset": "LINK", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "LINK/GBP" }, { "id": "LINKBTC", "asset": "LINK", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "LINK/BTC" }, { "id": "LINKETH", "asset": "LINK", "currency": "ETH", "min_size": "0.00000001", "min_total": "0.005", "increment": "0.00000001", "label": "LINK/ETH" }, { "id": "XLMBTC", "asset": "XLM", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "XLM/BTC" }, { "id": "XLMUSD", "asset": "XLM", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XLM/USD" }, { "id": "XLMEUR", "asset": "XLM", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XLM/EUR" }, { "id": "XLMGBP", "asset": "XLM", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "XLM/GBP" }, { "id": "BCHUSD", "asset": "BCH", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BCH/USD" }, { "id": "BCHEUR", "asset": "BCH", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BCH/EUR" }, { "id": "BCHBTC", "asset": "BCH", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "BCH/BTC" }, { "id": "BCHGBP", "asset": "BCH", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "BCH/GBP" }, { "id": "AAVEUSD", "asset": "AAVE", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "AAVE/USD" }, { "id": "AAVEEUR", "asset": "AAVE", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "AAVE/EUR" }, { "id": "AAVEBTC", "asset": "AAVE", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "AAVE/BTC" }, { "id": "ALGOUSD", "asset": "ALGO", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "ALGO/USD" }, { "id": "ALGOEUR", "asset": "ALGO", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "ALGO/EUR" }, { "id": "ALGOBTC", "asset": "ALGO", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "ALGO/BTC" }, { "id": "SNXUSD", "asset": "SNX", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "SNX/USD" }, { "id": "SNXEUR", "asset": "SNX", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "SNX/EUR" }, { "id": "SNXBTC", "asset": "SNX", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "SNX/BTC" }, { "id": "BATUSD", "asset": "BAT", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "BAT/USD" }, { "id": "BATEUR", "asset": "BAT", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "BAT/EUR" }, { "id": "BATBTC", "asset": "BAT", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "BAT/BTC" }, { "id": "MKRUSD", "asset": "MKR", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "MKR/USD" }, { "id": "MKREUR", "asset": "MKR", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "MKR/EUR" }, { "id": "MKRBTC", "asset": "MKR", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "MKR/BTC" }, { "id": "ZRXUSD", "asset": "ZRX", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "ZRX/USD" }, { "id": "ZRXEUR", "asset": "ZRX", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "ZRX/EUR" }, { "id": "ZRXBTC", "asset": "ZRX", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "ZRX/BTC" }, { "id": "YFIUSD", "asset": "YFI", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "YFI/USD" }, { "id": "YFIEUR", "asset": "YFI", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "YFI/EUR" }, { "id": "YFIBTC", "asset": "YFI", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "YFI/BTC" }, { "id": "UMAUSD", "asset": "UMA", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "UMA/USD" }, { "id": "UMAEUR", "asset": "UMA", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "UMA/EUR" }, { "id": "UMABTC", "asset": "UMA", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "UMA/BTC" }, { "id": "OMGUSD", "asset": "OMG", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "OMG/USD" }, { "id": "OMGEUR", "asset": "OMG", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "OMG/EUR" }, { "id": "OMGGBP", "asset": "OMG", "currency": "GBP", "min_size": "0.00000001", "min_total": "20", "increment": "0.01", "label": "OMG/GBP" }, { "id": "OMGBTC", "asset": "OMG", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "OMG/BTC" }, { "id": "KNCUSD", "asset": "KNC", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "KNC/USD" }, { "id": "KNCEUR", "asset": "KNC", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "KNC/EUR" }, { "id": "KNCBTC", "asset": "KNC", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "KNC/BTC" }, { "id": "CRVUSD", "asset": "CRV", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "CRV/USD" }, { "id": "CRVEUR", "asset": "CRV", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "CRV/EUR" }, { "id": "CRVBTC", "asset": "CRV", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "CRV/BTC" }, { "id": "AUDIOUSD", "asset": "AUDIO", "currency": "USD", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "AUDIO/USD" }, { "id": "AUDIOEUR", "asset": "AUDIO", "currency": "EUR", "min_size": "0.00000001", "min_total": "20", "increment": "0.00001", "label": "AUDIO/EUR" }, { "id": "AUDIOBTC", "asset": "AUDIO", "currency": "BTC", "min_size": "0.00000001", "min_total": "0.0002", "increment": "0.00000001", "label": "AUDIO/BTC" }, { "id": "USDCUSD", "asset": "USDC", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "USDC/USD" }, { "id": "USDCEUR", "asset": "USDC", "currency": "EUR", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "USDC/EUR" }, { "id": "DAIUSD", "asset": "DAI", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "DAI/USD" }, { "id": "PAXUSD", "asset": "PAX", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "PAX/USD" }, { "id": "PAXEUR", "asset": "PAX", "currency": "EUR", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "PAX/EUR" }, { "id": "PAXGBP", "asset": "PAX", "currency": "GBP", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "PAX/GBP" }, { "id": "ETH2ETH", "asset": "ETH2", "currency": "ETH", "min_size": "0.00000001", "min_total": "0.005", "increment": "0.00000001", "label": "ETH2/ETH" }, { "id": "GUSDUSD", "asset": "GUSD", "currency": "USD", "min_size": "0.00001", "min_total": "20", "increment": "0.00001", "label": "GUSD/USD" } ] ================================================ FILE: extensions/exchanges/bitstamp/update-products.sh ================================================ #!/usr/bin/env node let ccxt = require('ccxt') new ccxt.bitstamp().fetch_markets().then(function(markets) { var products = [] var products = markets.map(function (market) { return { id: market.id.toUpperCase(), asset: market.base, currency: market.quote, min_size: market.limits.amount.min.toFixed(market.precision.amount), min_total: market.limits.cost.min.toString(), increment: Math.pow(10, -market.precision.price).toFixed(market.precision.price), label: market.base + '/' + market.quote } }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/bittrex/exchange.js ================================================ var bittrex_authed = require('node-bittrex-api'), bittrex_public = require('node-bittrex-api'), n = require('numbro') module.exports = function bittrex(conf) { let recoverableErrors = new RegExp(/(ESOCKETTIMEOUT|ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|Invalid nonce|Rate limit exceeded|URL request error)/) let shownWarning = false let firstRun = true let allowGetMarketCall = true let marketRefresh = 15000 bittrex_authed.options({ 'apikey': conf.bittrex.key.trim(), 'apisecret': conf.bittrex.secret.trim(), 'stream': false, 'cleartext': false, 'verbose': false }) function joinProduct(product_id) { return product_id.split('-')[1] + '-' + product_id.split('-')[0] } function retry(method, args, error) { var timeout = 2500 if (error) if (error.message) if (error.message.match(/Rate limit exceeded/)) { timeout = 10000 } setTimeout(function () { exchange[method].apply(exchange, args) }, timeout) return false } function handleErrors(command, err, data, args, callback) { if (err) { if (err.message && err.message.match(recoverableErrors)) { return retry(command, args, err) } return callback(err, []) } if (typeof data !== 'object') { console.log(`Bittrex API ${command} had an abnormal response, quitting.`) return callback(null, []) } // generic error handler data was null and err was null if (data == null) { return retry(command, args, err) } // specific handlers if ((command == 'getQuote' || command == 'getTrades') && data.result == null ) { return retry(command, args, data) } if (!data.success) { if (data.message && data.message.match(recoverableErrors)) { return retry(command, args, data.message) } return callback(null, []) } return true } var orders = {} var exchange = { name: 'bittrex', historyScan: 'forward', makerFee: 0.25, takerFee: 0.25, getProducts: function() { return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var args = { market:joinProduct(opts.product_id), marketName: joinProduct(opts.product_id), tickInterval: 'oneMin' } // accomplish back trades using 2 calls. ticks and getMarket and create a hybrid result. var trades = [] // first run do the full deal. 2nd run only returns the last trades if (allowGetMarketCall != true) { cb(null, []) return null } if (firstRun) { bittrex_public.getticks(args, function(data, err) { let res = handleErrors('getTrades', err, data, func_args, cb) if (!shownWarning) { console.log('Bittrex backfill is indirectly supported through the use of a hybrid system that combines a low resolution') console.log('long term market of about 10 days and a short term high resolution market of the last 1-5 minutes.') shownWarning = true } if (res) { let lastVal = 0 for (const key in Object.keys(data.result)) { var trade = data.result[key] if (isNaN(opts.from) || new Date(trade.T).getTime() > new Date(opts.from).getTime()) { let buySell = 'sell' // todo: unsure about the >. if the price is greater than the last one should this one be a buy or sell. figure it out. if (parseFloat(trade.C) > lastVal) buySell = 'buy' trades.push({ trade_id: new Date(trade.T).getTime(), time: new Date(trade.T).getTime(), size: parseFloat(trade.V), price: parseFloat(trade.C), // selector should get overwritten by backfill, but was a point where it was missing in the backfill function so this was put in so it is never missed selector: 'bittrex.'+opts.product_id, side: buySell }) lastVal = parseFloat(trade.C) } } bittrex_public.getmarkethistory(args, function(data, err) { let res2 = handleErrors('getTrades', err, data, func_args, cb) if (res2) { for (const key in Object.keys(data.result)) { var trade = data.result[key] if (isNaN(opts.from) || new Date(trade.TimeStamp).getTime() > new Date(opts.from).getTime()) { trades.push({ // trade_id: trade.Id, trade_id: trade.id, time: new Date(trade.TimeStamp).getTime(), size: parseFloat(trade.Quantity), price: parseFloat(trade.Price), // selector should get overwritten by backfill, but was a point where it was missing in the backfill function so this was put in so it is never missed selector: 'bittrex.'+opts.product_id, side: trade.OrderType || trade.OrderType == 'SELL' ? 'sell': 'buy' // selector: }) } } firstRun = false allowGetMarketCall = false setTimeout(()=>{allowGetMarketCall = true},marketRefresh) // make sure all times come out sorted correctly. there is a chance they can appear in the array out of order otherwise. trades = trades.sort((a, b) => { if (a.time < b.time) return 1 if (a.time > b.time) return -1 return 0 } ) cb(null, trades) } }) } }) } else { bittrex_public.getmarkethistory(args, function(data, err) { let res2 = handleErrors('getTrades', err, data, func_args, cb) if (res2) { for (const key in Object.keys(data.result)) { var trade = data.result[key] if (isNaN(opts.from) || new Date(trade.TimeStamp).getTime() > new Date(opts.from).getTime()) { trades.push({ // trade_id: trade.Id, trade_id: new Date(trade.TimeStamp).getTime(), time: new Date(trade.TimeStamp).getTime(), size: parseFloat(trade.Quantity), price: parseFloat(trade.Price), // selector should get overwritten by backfill, but was a point where it was missing in the backfill function so this was put in so it is never missed selector: 'bittrex.'+opts.product_id, side: trade.OrderType || trade.OrderType == 'SELL' ? 'sell': 'buy' }) } } allowGetMarketCall = false setTimeout(()=>{allowGetMarketCall = true},marketRefresh) // Sorting at this point may be redundant. trades = trades.sort((a, b) => { if (a.time < b.time) return 1 if (a.time > b.time) return -1 return 0 } ) cb(null, trades) } }) } }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) bittrex_authed.getbalances(function(data,err ) { let res = handleErrors('getBalance', err, data, func_args, cb) var balance = { asset: 0, currency: 0 } if (res) { for (const key in data.result) { var _balance = data.result[key] if (opts.last_signal === 'buy') { if (_balance['Currency'] === opts.currency.toUpperCase()) { balance.currency = n(_balance.Available).format('0.00000000'), balance.currency_hold = 0 } if (_balance['Currency'] === opts.asset.toUpperCase()) { balance.asset = n(_balance.Available).format('0.00000000'), balance.asset_hold = 0 } } else { if (_balance['Currency'] === opts.asset.toUpperCase()) { balance.asset = n(_balance.Available).format('0.00000000'), balance.asset_hold = 0 } if (_balance['Currency'] === opts.currency.toUpperCase()) { balance.currency = n(_balance.Available).format('0.00000000'), balance.currency_hold = 0 } } } cb(null, balance) } }) }, getOrderBook: function (opts, cb) { var args = { market: joinProduct(opts.product_id), type: 'both', depth: 10 } bittrex_public.getorderbook(args, function(data) { if (typeof data !== 'object') { console.log('Bittrex API (getorderbook) had an abnormal response, quitting.') return cb(null, []) } if (!data.success) { if (data.message && data.message.match(recoverableErrors)) { return retry('getOrderBook', args, data.message) } console.log(data.message) return cb(null, []) } if (typeof data.result.buy[0].Rate === 'undefined') { console.log(data.message) return cb(null, []) } cb(null, { buyOrderRate: data.result.buy[0].Rate, buyOrderAmount: data.result.buy[0].Quantity, sellOrderRate: data.result.sell[0].Rate, sellOrderAmount: data.result.sell[0].Quantity }) }) }, getQuote: function (opts, cb) { if (opts == null) return if (opts.product_id == null) return var func_args = [].slice.call(arguments) var args = { market: joinProduct(opts.product_id) } bittrex_public.getticker(args, function(data, err ) { let res = handleErrors('getQuote', err, data, func_args, cb) if (res) cb(null, { bid: data.result.Bid, ask: data.result.Ask }) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) let args = { uuid: opts.order_id } bittrex_authed.cancel(args, function (data, err) { if (err) { return retry('cancelOrder', func_args, err) } cb() }) }, trade: function (type, opts, cb) { var func_args = [].slice.call(arguments) var params = { market: joinProduct(opts.product_id), quantity: opts.size, rate: opts.price } if (!('order_type' in opts) || !opts.order_type) { opts.order_type = 'maker' } var fn = function(data,err) { if (err != null ) { if (data == null) { data = {} data.message = err.message data.success = err.success data.result = err.result } console.log('API Error') console.log(JSON.stringify(err)) if (err.message && err.message.match(recoverableErrors)) { return retry('trade', func_args, err.message) } } if (err && err.message) { if (err.message =='MIN_TRADE_REQUIREMENT_NOT_MET') { let returnResult = { reject_reason:'balance', status:'rejected' } return cb(null, returnResult) } } if (typeof data !== 'object') { return cb(null, {}) } if (!data.success) { if (data.message && data.message.match(recoverableErrors)) { return retry('trade', func_args, data.message) } console.log(data.message) return cb(null, []) } var order = { id: data && data.result ? data.result.uuid : null, status: 'open', price: opts.price, size: opts.size, post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } orders['~' + data.result.uuid] = order cb(null, order) } if (type === 'buy') { if (opts.order_type === 'maker') { bittrex_authed.buylimit(params, fn) } if (opts.order_type === 'taker') { bittrex_authed.buymarket(params, fn) } } if (type === 'sell') { if (opts.order_type === 'maker') { bittrex_authed.selllimit(params, fn) } if (opts.order_type === 'taker') { bittrex_authed.sellmarket(params, fn) } } }, buy: function (opts, cb) { exchange.trade('buy', opts, cb) }, sell: function (opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function(opts, cb) { var func_args = [].slice.call(arguments) var order = orders['~' + opts.order_id] if (!order) return cb(new Error('order not found in cache')) var params = { uuid: opts.order_id } bittrex_authed.getorder(params, function(data, err) { let res = handleErrors('getOrder', err, data, func_args, cb) if (res) { var orderData = data.result if (!orderData) { return cb('Order not found') } if (orderData.QuantityRemaining == 0) { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = parseFloat(orderData.Quantity) - parseFloat(orderData.QuantityRemaining) return cb(null, order) } cb(null, order) } }) }, // return the property used for range querying. getCursor: function (trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/bittrex/products.json ================================================ [ { "asset": "LTC", "currency": "BTC", "min_size": "0.01156120", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LTC" }, { "asset": "DOGE", "currency": "BTC", "min_size": "7.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DOGE" }, { "asset": "VTC", "currency": "BTC", "min_size": "1.67649800", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VTC" }, { "asset": "PPC", "currency": "BTC", "min_size": "3.20665080", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PPC" }, { "asset": "FTC", "currency": "BTC", "min_size": "62.06896550", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FTC" }, { "asset": "RDD", "currency": "BTC", "min_size": "415.38461540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RDD" }, { "asset": "NXT", "currency": "BTC", "min_size": "38.29787240", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NXT" }, { "asset": "POT", "currency": "BTC", "min_size": "58.06451610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/POT" }, { "asset": "BLK", "currency": "BTC", "min_size": "29.34782610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BLK" }, { "asset": "EMC2", "currency": "BTC", "min_size": "6.75000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EMC2" }, { "asset": "XMY", "currency": "BTC", "min_size": "490.90909090", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XMY" }, { "asset": "GRS", "currency": "BTC", "min_size": "2.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GRS" }, { "asset": "NLG", "currency": "BTC", "min_size": "90.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NLG" }, { "asset": "XWC", "currency": "BTC", "min_size": "1.89274450", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XWC" }, { "asset": "MONA", "currency": "BTC", "min_size": "0.92449920", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MONA" }, { "asset": "THC", "currency": "BTC", "min_size": "110.20408160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/THC" }, { "asset": "VRC", "currency": "BTC", "min_size": "21.09375000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VRC" }, { "asset": "CURE", "currency": "BTC", "min_size": "16.66666670", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CURE" }, { "asset": "XDN", "currency": "BTC", "min_size": "380.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XDN" }, { "asset": "NAV", "currency": "BTC", "min_size": "4.58015270", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NAV" }, { "asset": "XST", "currency": "BTC", "min_size": "16.51376150", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XST" }, { "asset": "AR", "currency": "BTC", "min_size": "0.12495660", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AR" }, { "asset": "VIA", "currency": "BTC", "min_size": "1.94384450", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VIA" }, { "asset": "PINK", "currency": "BTC", "min_size": "135.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PINK" }, { "asset": "IOC", "currency": "BTC", "min_size": "11.84210530", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IOC" }, { "asset": "SYS", "currency": "BTC", "min_size": "7.61636110", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SYS" }, { "asset": "DGB", "currency": "BTC", "min_size": "22.40663900", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DGB" }, { "asset": "BURST", "currency": "BTC", "min_size": "192.85714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BURST" }, { "asset": "EXCL", "currency": "BTC", "min_size": "10.07462690", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EXCL" }, { "asset": "BLOCK", "currency": "BTC", "min_size": "0.72019210", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BLOCK" }, { "asset": "BTS", "currency": "BTC", "min_size": "27.13567840", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTS" }, { "asset": "XRP", "currency": "BTC", "min_size": "2.30572160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XRP" }, { "asset": "GAME", "currency": "BTC", "min_size": "11.20331950", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GAME" }, { "asset": "NXS", "currency": "BTC", "min_size": "2.04622960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NXS" }, { "asset": "GEO", "currency": "BTC", "min_size": "3.61687880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GEO" }, { "asset": "FLO", "currency": "BTC", "min_size": "37.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FLO" }, { "asset": "MUE", "currency": "BTC", "min_size": "128.57142860", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MUE" }, { "asset": "XEM", "currency": "BTC", "min_size": "7.81476120", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XEM" }, { "asset": "SPHR", "currency": "BTC", "min_size": "7.79220780", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SPHR" }, { "asset": "OK", "currency": "BTC", "min_size": "42.18750000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OK" }, { "asset": "AEON", "currency": "BTC", "min_size": "2.88770050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AEON" }, { "asset": "ETH", "currency": "BTC", "min_size": "0.00140180", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ETH" }, { "asset": "EXP", "currency": "BTC", "min_size": "18.55670100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EXP" }, { "asset": "AGRS", "currency": "BTC", "min_size": "2.42914980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AGRS" }, { "asset": "XLM", "currency": "BTC", "min_size": "5.94059410", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XLM" }, { "asset": "BTC", "currency": "USDT", "min_size": "0.00005460", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BTC" }, { "asset": "FCT", "currency": "BTC", "min_size": "1.23910050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FCT" }, { "asset": "MAID", "currency": "BTC", "min_size": "2.66140960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MAID" }, { "asset": "SLS", "currency": "BTC", "min_size": "0.07714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SLS" }, { "asset": "VAL", "currency": "BTC", "min_size": "0.90863200", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VAL" }, { "asset": "DCR", "currency": "BTC", "min_size": "0.01392710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DCR" }, { "asset": "XVG", "currency": "BTC", "min_size": "50.46728970", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XVG" }, { "asset": "PIVX", "currency": "BTC", "min_size": "1.84552290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PIVX" }, { "asset": "MEME", "currency": "BTC", "min_size": "55.10204080", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MEME" }, { "asset": "STEEM", "currency": "BTC", "min_size": "3.04912480", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STEEM" }, { "asset": "LSK", "currency": "BTC", "min_size": "0.55739060", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LSK" }, { "asset": "WAVES", "currency": "BTC", "min_size": "0.23685250", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WAVES" }, { "asset": "LBC", "currency": "BTC", "min_size": "15.56195960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LBC" }, { "asset": "SBD", "currency": "BTC", "min_size": "0.38916110", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SBD" }, { "asset": "ETC", "currency": "BTC", "min_size": "0.08854350", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ETC" }, { "asset": "ETC", "currency": "ETH", "min_size": "0.08880250", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ETC" }, { "asset": "STRAX", "currency": "BTC", "min_size": "1.46301820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STRAX" }, { "asset": "REPV2", "currency": "BTC", "min_size": "0.07004980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/REPV2" }, { "asset": "ARDR", "currency": "BTC", "min_size": "8.30769230", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ARDR" }, { "asset": "FIRO", "currency": "BTC", "min_size": "0.23710210", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FIRO" }, { "asset": "NEO", "currency": "BTC", "min_size": "0.02727320", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NEO" }, { "asset": "UBQ", "currency": "BTC", "min_size": "5.04672900", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UBQ" }, { "asset": "KMD", "currency": "BTC", "min_size": "1.08870970", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KMD" }, { "asset": "SIB", "currency": "BTC", "min_size": "48.64864870", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SIB" }, { "asset": "CRW", "currency": "BTC", "min_size": "19.14893620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CRW" }, { "asset": "ARK", "currency": "BTC", "min_size": "1.48883380", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ARK" }, { "asset": "GBYTE", "currency": "BTC", "min_size": "0.03532140", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GBYTE" }, { "asset": "GLM", "currency": "BTC", "min_size": "6.70807450", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GLM" }, { "asset": "MORE", "currency": "BTC", "min_size": "31.95266270", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MORE" }, { "asset": "GLM", "currency": "ETH", "min_size": "6.67866620", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/GLM" }, { "asset": "REPV2", "currency": "ETH", "min_size": "0.07289300", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/REPV2" }, { "asset": "ETH", "currency": "USDT", "min_size": "0.00141900", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ETH" }, { "asset": "WINGS", "currency": "BTC", "min_size": "27.97927460", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WINGS" }, { "asset": "RLC", "currency": "BTC", "min_size": "1.34730540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RLC" }, { "asset": "GNO", "currency": "BTC", "min_size": "0.01780160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GNO" }, { "asset": "GNO", "currency": "ETH", "min_size": "0.01711170", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/GNO" }, { "asset": "HMQ", "currency": "BTC", "min_size": "337.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HMQ" }, { "asset": "ANT", "currency": "BTC", "min_size": "0.35495960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ANT" }, { "asset": "ANT", "currency": "ETH", "min_size": "0.35864990", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ANT" }, { "asset": "SC", "currency": "BTC", "min_size": "71.05263160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SC" }, { "asset": "BAT", "currency": "ETH", "min_size": "2.45610370", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BAT" }, { "asset": "BAT", "currency": "BTC", "min_size": "2.43133730", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BAT" }, { "asset": "ZEN", "currency": "BTC", "min_size": "0.03111370", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ZEN" }, { "asset": "QRL", "currency": "BTC", "min_size": "6.39053250", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/QRL" }, { "asset": "PTOY", "currency": "BTC", "min_size": "150.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PTOY" }, { "asset": "MYST", "currency": "BTC", "min_size": "7.30717190", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MYST" }, { "asset": "BNT", "currency": "BTC", "min_size": "0.44817000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BNT" }, { "asset": "BNT", "currency": "ETH", "min_size": "0.45472870", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BNT" }, { "asset": "NMR", "currency": "BTC", "min_size": "0.04181380", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NMR" }, { "asset": "NMR", "currency": "ETH", "min_size": "0.04295450", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/NMR" }, { "asset": "LTC", "currency": "ETH", "min_size": "0.01159090", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/LTC" }, { "asset": "XRP", "currency": "ETH", "min_size": "2.31976570", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/XRP" }, { "asset": "SNT", "currency": "BTC", "min_size": "15.65217390", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SNT" }, { "asset": "SNT", "currency": "ETH", "min_size": "15.90524540", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SNT" }, { "asset": "ADT", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ADT" }, { "asset": "PAY", "currency": "BTC", "min_size": "24.32432430", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PAY" }, { "asset": "PAY", "currency": "ETH", "min_size": "24.36495590", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/PAY" }, { "asset": "MTL", "currency": "BTC", "min_size": "0.80428950", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MTL" }, { "asset": "STORJ", "currency": "BTC", "min_size": "1.59763310", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STORJ" }, { "asset": "ADX", "currency": "BTC", "min_size": "2.55560810", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ADX" }, { "asset": "ADX", "currency": "ETH", "min_size": "2.59802480", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ADX" }, { "asset": "SC", "currency": "ETH", "min_size": "71.64634150", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SC" }, { "asset": "LTC", "currency": "USDT", "min_size": "0.01169830", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LTC" }, { "asset": "ETC", "currency": "USDT", "min_size": "0.08933630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ETC" }, { "asset": "XRP", "currency": "USDT", "min_size": "2.32558140", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XRP" }, { "asset": "OMG", "currency": "BTC", "min_size": "0.36525980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OMG" }, { "asset": "OMG", "currency": "ETH", "min_size": "0.36538910", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/OMG" }, { "asset": "CVC", "currency": "BTC", "min_size": "5.86319220", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CVC" }, { "asset": "CVC", "currency": "ETH", "min_size": "5.87500000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CVC" }, { "asset": "PART", "currency": "BTC", "min_size": "2.03927490", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PART" }, { "asset": "QTUM", "currency": "BTC", "min_size": "0.16086750", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/QTUM" }, { "asset": "QTUM", "currency": "ETH", "min_size": "0.16073870", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/QTUM" }, { "asset": "XEM", "currency": "ETH", "min_size": "7.88458310", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/XEM" }, { "asset": "XLM", "currency": "ETH", "min_size": "5.97432310", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/XLM" }, { "asset": "NEO", "currency": "ETH", "min_size": "0.02745740", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/NEO" }, { "asset": "BCH", "currency": "ETH", "min_size": "0.00332110", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BCH" }, { "asset": "BCH", "currency": "USDT", "min_size": "0.00334660", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BCH" }, { "asset": "BCH", "currency": "BTC", "min_size": "0.00330630", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BCH" }, { "asset": "DNT", "currency": "BTC", "min_size": "8.33333330", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DNT" }, { "asset": "NEO", "currency": "USDT", "min_size": "0.02735660", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NEO" }, { "asset": "WAVES", "currency": "ETH", "min_size": "0.24172890", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/WAVES" }, { "asset": "STRAX", "currency": "ETH", "min_size": "1.47478740", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/STRAX" }, { "asset": "DGB", "currency": "ETH", "min_size": "22.50239390", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/DGB" }, { "asset": "OMG", "currency": "USDT", "min_size": "0.36684390", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/OMG" }, { "asset": "ADA", "currency": "BTC", "min_size": "2.48390060", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ADA" }, { "asset": "MANA", "currency": "BTC", "min_size": "2.48504370", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MANA" }, { "asset": "MANA", "currency": "ETH", "min_size": "2.46318330", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/MANA" }, { "asset": "RCN", "currency": "BTC", "min_size": "23.17596570", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RCN" }, { "asset": "VIB", "currency": "BTC", "min_size": "21.42857140", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VIB" }, { "asset": "VIB", "currency": "ETH", "min_size": "22.04158200", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/VIB" }, { "asset": "MER", "currency": "BTC", "min_size": "108.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MER" }, { "asset": "POWR", "currency": "BTC", "min_size": "7.12401050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/POWR" }, { "asset": "POWR", "currency": "ETH", "min_size": "7.12157180", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/POWR" }, { "asset": "ADA", "currency": "ETH", "min_size": "2.49213470", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ADA" }, { "asset": "ENG", "currency": "BTC", "min_size": "18.81533100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ENG" }, { "asset": "ENG", "currency": "ETH", "min_size": "18.77746700", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ENG" }, { "asset": "ADA", "currency": "USDT", "min_size": "2.51018480", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ADA" }, { "asset": "XVG", "currency": "USDT", "min_size": "50.91119150", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XVG" }, { "asset": "IGNIS", "currency": "BTC", "min_size": "20.37735850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IGNIS" }, { "asset": "SRN", "currency": "BTC", "min_size": "110.20408160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SRN" }, { "asset": "SRN", "currency": "ETH", "min_size": "110.84905660", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SRN" }, { "asset": "WAXP", "currency": "BTC", "min_size": "14.87603310", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WAXP" }, { "asset": "WAXP", "currency": "ETH", "min_size": "14.88283730", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/WAXP" }, { "asset": "ZRX", "currency": "BTC", "min_size": "1.83923710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ZRX" }, { "asset": "ZRX", "currency": "ETH", "min_size": "1.85012660", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ZRX" }, { "asset": "VEE", "currency": "BTC", "min_size": "540.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VEE" }, { "asset": "TRX", "currency": "BTC", "min_size": "22.40663900", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TRX" }, { "asset": "TRX", "currency": "ETH", "min_size": "22.38805970", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/TRX" }, { "asset": "TUSD", "currency": "BTC", "min_size": "2.96866410", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TUSD" }, { "asset": "LRC", "currency": "BTC", "min_size": "5.40000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LRC" }, { "asset": "TUSD", "currency": "ETH", "min_size": "3.00485890", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/TUSD" }, { "asset": "DMT", "currency": "BTC", "min_size": "3.00166760", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DMT" }, { "asset": "DMT", "currency": "ETH", "min_size": "2.83360130", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/DMT" }, { "asset": "TUSD", "currency": "USDT", "min_size": "3.00902710", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TUSD" }, { "asset": "SC", "currency": "USDT", "min_size": "73.26241700", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SC" }, { "asset": "TRX", "currency": "USDT", "min_size": "22.59967870", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TRX" }, { "asset": "STMX", "currency": "BTC", "min_size": "59.34065930", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STMX" }, { "asset": "STMX", "currency": "ETH", "min_size": "57.85802220", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/STMX" }, { "asset": "AID", "currency": "BTC", "min_size": "75.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AID" }, { "asset": "NGC", "currency": "BTC", "min_size": "62.06896550", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NGC" }, { "asset": "GTO", "currency": "BTC", "min_size": "40.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GTO" }, { "asset": "DCR", "currency": "USDT", "min_size": "0.01419470", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DCR" }, { "asset": "BTC", "currency": "USD", "min_size": "0.00005450", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BTC" }, { "asset": "USDT", "currency": "USD", "min_size": "2.99508810", "max_size": "1000000", "increment": "0.00000001", "label": "USD/USDT" }, { "asset": "TUSD", "currency": "USD", "min_size": "3.00108040", "max_size": "1000000", "increment": "0.00000001", "label": "USD/TUSD" }, { "asset": "TUBE", "currency": "BTC", "min_size": "150.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TUBE" }, { "asset": "CBC", "currency": "BTC", "min_size": "33.12883440", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CBC" }, { "asset": "ETH", "currency": "USD", "min_size": "0.00141630", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ETH" }, { "asset": "MFT", "currency": "BTC", "min_size": "192.85714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MFT" }, { "asset": "LOOM", "currency": "BTC", "min_size": "22.04081630", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LOOM" }, { "asset": "DGB", "currency": "USDT", "min_size": "22.72634300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DGB" }, { "asset": "RVN", "currency": "BTC", "min_size": "16.21621620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RVN" }, { "asset": "XRP", "currency": "USD", "min_size": "2.32153220", "max_size": "1000000", "increment": "0.00000001", "label": "USD/XRP" }, { "asset": "ETC", "currency": "USD", "min_size": "0.08823530", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ETC" }, { "asset": "BFT", "currency": "BTC", "min_size": "49.09090910", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BFT" }, { "asset": "GO", "currency": "BTC", "min_size": "63.52941180", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GO" }, { "asset": "HYDRO", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HYDRO" }, { "asset": "UPP", "currency": "BTC", "min_size": "18.81533100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPP" }, { "asset": "ADA", "currency": "USD", "min_size": "2.51033420", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ADA" }, { "asset": "DOGE", "currency": "USDT", "min_size": "7.80598490", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DOGE" }, { "asset": "ENJ", "currency": "BTC", "min_size": "1.21841150", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ENJ" }, { "asset": "MET", "currency": "BTC", "min_size": "0.95456960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MET" }, { "asset": "LTC", "currency": "USD", "min_size": "0.01165440", "max_size": "1000000", "increment": "0.00000001", "label": "USD/LTC" }, { "asset": "TRX", "currency": "USD", "min_size": "22.55639100", "max_size": "1000000", "increment": "0.00000001", "label": "USD/TRX" }, { "asset": "DTA", "currency": "BTC", "min_size": "1080.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DTA" }, { "asset": "EDR", "currency": "BTC", "min_size": "50.94339620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EDR" }, { "asset": "BCH", "currency": "USD", "min_size": "0.00332020", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BCH" }, { "asset": "XHV", "currency": "BTC", "min_size": "0.14191480", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XHV" }, { "asset": "ZRX", "currency": "USDT", "min_size": "1.85583200", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ZRX" }, { "asset": "NPXS", "currency": "BTC", "min_size": "771.42857140", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NPXS" }, { "asset": "PMA", "currency": "BTC", "min_size": "2700.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PMA" }, { "asset": "BAT", "currency": "USDT", "min_size": "2.45314320", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BAT" }, { "asset": "RVN", "currency": "USDT", "min_size": "16.37651750", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RVN" }, { "asset": "SC", "currency": "USD", "min_size": "71.34363850", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SC" }, { "asset": "PAX", "currency": "BTC", "min_size": "3.00333710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PAX" }, { "asset": "ZIL", "currency": "BTC", "min_size": "16.21621620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ZIL" }, { "asset": "MOC", "currency": "BTC", "min_size": "19.49458490", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MOC" }, { "asset": "SPC", "currency": "BTC", "min_size": "49.54128440", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SPC" }, { "asset": "MED", "currency": "BTC", "min_size": "26.47058820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MED" }, { "asset": "BSV", "currency": "BTC", "min_size": "0.00999460", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BSV" }, { "asset": "IOST", "currency": "BTC", "min_size": "41.53846160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IOST" }, { "asset": "BSV", "currency": "USDT", "min_size": "0.01028840", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BSV" }, { "asset": "BSV", "currency": "ETH", "min_size": "0.01012210", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BSV" }, { "asset": "SOLVE", "currency": "BTC", "min_size": "11.36842100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SOLVE" }, { "asset": "USDS", "currency": "BTC", "min_size": "2.98013240", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/USDS" }, { "asset": "PMA", "currency": "USDT", "min_size": "6665.18551430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PMA" }, { "asset": "NPXS", "currency": "ETH", "min_size": "783.33333330", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/NPXS" }, { "asset": "NPXS", "currency": "USDT", "min_size": "789.47368420", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NPXS" }, { "asset": "ZRX", "currency": "USD", "min_size": "1.84153020", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ZRX" }, { "asset": "BAT", "currency": "USD", "min_size": "2.45491150", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BAT" }, { "asset": "BSV", "currency": "USD", "min_size": "0.01025640", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BSV" }, { "asset": "USDS", "currency": "USD", "min_size": "2.99832090", "max_size": "1000000", "increment": "0.00000001", "label": "USD/USDS" }, { "asset": "DRGN", "currency": "BTC", "min_size": "12.79620850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DRGN" }, { "asset": "PAX", "currency": "USD", "min_size": "3.00150080", "max_size": "1000000", "increment": "0.00000001", "label": "USD/PAX" }, { "asset": "VITE", "currency": "BTC", "min_size": "15.88235300", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VITE" }, { "asset": "IOTX", "currency": "BTC", "min_size": "68.35443040", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IOTX" }, { "asset": "DGB", "currency": "USD", "min_size": "22.54791430", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DGB" }, { "asset": "BTM", "currency": "BTC", "min_size": "12.85714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTM" }, { "asset": "QNT", "currency": "BTC", "min_size": "0.07444680", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/QNT" }, { "asset": "BTU", "currency": "BTC", "min_size": "6.01336300", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTU" }, { "asset": "ZEN", "currency": "USD", "min_size": "0.03090210", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ZEN" }, { "asset": "BTT", "currency": "BTC", "min_size": "385.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTT" }, { "asset": "NKN", "currency": "BTC", "min_size": "4.94505500", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NKN" }, { "asset": "KMD", "currency": "USD", "min_size": "1.10375280", "max_size": "1000000", "increment": "0.00000001", "label": "USD/KMD" }, { "asset": "BTT", "currency": "USDT", "min_size": "393.50197080", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BTT" }, { "asset": "GRIN", "currency": "BTC", "min_size": "3.13588850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GRIN" }, { "asset": "CTXC", "currency": "BTC", "min_size": "23.27746741", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CTXC" }, { "asset": "HXRO", "currency": "BTC", "min_size": "4.93150690", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HXRO" }, { "asset": "META", "currency": "BTC", "min_size": "17.47572820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/META" }, { "asset": "GRIN", "currency": "USDT", "min_size": "3.46151720", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GRIN" }, { "asset": "FSN", "currency": "BTC", "min_size": "2.23417460", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FSN" }, { "asset": "ANKR", "currency": "BTC", "min_size": "19.49458490", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ANKR" }, { "asset": "XLM", "currency": "USDT", "min_size": "5.99610320", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XLM" }, { "asset": "TRAC", "currency": "BTC", "min_size": "4.95412850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TRAC" }, { "asset": "CRO", "currency": "BTC", "min_size": "15.29745040", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CRO" }, { "asset": "ONT", "currency": "BTC", "min_size": "1.34562670", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ONT" }, { "asset": "SOLVE", "currency": "ETH", "min_size": "11.61928310", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SOLVE" }, { "asset": "ONG", "currency": "BTC", "min_size": "2.60743600", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ONG" }, { "asset": "MARO", "currency": "BTC", "min_size": "7.39726030", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MARO" }, { "asset": "PTON", "currency": "BTC", "min_size": "5400.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PTON" }, { "asset": "PI", "currency": "BTC", "min_size": "65.06024100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PI" }, { "asset": "ANKR", "currency": "ETH", "min_size": "19.52097470", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ANKR" }, { "asset": "PLA", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PLA" }, { "asset": "ORBS", "currency": "BTC", "min_size": "20.07434940", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ORBS" }, { "asset": "ENJ", "currency": "USDT", "min_size": "1.21354960", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ENJ" }, { "asset": "VBK", "currency": "BTC", "min_size": "186.20689660", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VBK" }, { "asset": "BORA", "currency": "BTC", "min_size": "13.36633660", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BORA" }, { "asset": "CND", "currency": "BTC", "min_size": "90.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CND" }, { "asset": "ONT", "currency": "USDT", "min_size": "1.34633890", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ONT" }, { "asset": "FX", "currency": "BTC", "min_size": "4.17956660", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FX" }, { "asset": "FX", "currency": "ETH", "min_size": "4.00045400", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/FX" }, { "asset": "ATOM", "currency": "BTC", "min_size": "0.15273650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ATOM" }, { "asset": "ATOM", "currency": "USDT", "min_size": "0.15438460", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ATOM" }, { "asset": "ATOM", "currency": "ETH", "min_size": "0.15205420", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ATOM" }, { "asset": "OCEAN", "currency": "BTC", "min_size": "2.12431160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OCEAN" }, { "asset": "OCEAN", "currency": "USDT", "min_size": "2.16730200", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/OCEAN" }, { "asset": "BWX", "currency": "BTC", "min_size": "30.85714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BWX" }, { "asset": "SNX", "currency": "BTC", "min_size": "0.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SNX" }, { "asset": "VDX", "currency": "BTC", "min_size": "1350.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VDX" }, { "asset": "VDX", "currency": "USDT", "min_size": "1488.95936630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VDX" }, { "asset": "VDX", "currency": "ETH", "min_size": "1639.53488370", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/VDX" }, { "asset": "COSM", "currency": "BTC", "min_size": "1350.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/COSM" }, { "asset": "LAMB", "currency": "BTC", "min_size": "36.48648650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LAMB" }, { "asset": "STPT", "currency": "BTC", "min_size": "44.26229510", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STPT" }, { "asset": "MKR", "currency": "BTC", "min_size": "0.00087160", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MKR" }, { "asset": "MKR", "currency": "ETH", "min_size": "0.00088520", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/MKR" }, { "asset": "DAI", "currency": "BTC", "min_size": "2.98177800", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DAI" }, { "asset": "DAI", "currency": "ETH", "min_size": "2.94473920", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/DAI" }, { "asset": "DAI", "currency": "USDT", "min_size": "2.99662880", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DAI" }, { "asset": "FNB", "currency": "BTC", "min_size": "337.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FNB" }, { "asset": "PROM", "currency": "BTC", "min_size": "0.25714290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PROM" }, { "asset": "ABYSS", "currency": "BTC", "min_size": "45.76271190", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ABYSS" }, { "asset": "EOS", "currency": "BTC", "min_size": "0.44705690", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EOS" }, { "asset": "EOS", "currency": "ETH", "min_size": "0.44626890", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/EOS" }, { "asset": "EOS", "currency": "USDT", "min_size": "0.44981910", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/EOS" }, { "asset": "AMP", "currency": "BTC", "min_size": "52.94117650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AMP" }, { "asset": "DUSK", "currency": "BTC", "min_size": "10.44487430", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DUSK" }, { "asset": "URAC", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/URAC" }, { "asset": "BRZ", "currency": "BTC", "min_size": "16.77018630", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BRZ" }, { "asset": "TEMCO", "currency": "BTC", "min_size": "207.69230770", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TEMCO" }, { "asset": "SPIN", "currency": "BTC", "min_size": "2700.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SPIN" }, { "asset": "LUNA", "currency": "BTC", "min_size": "0.20987180", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LUNA" }, { "asset": "CHR", "currency": "BTC", "min_size": "58.13953488", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CHR" }, { "asset": "ARDX", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ARDX" }, { "asset": "ARDX", "currency": "ETH", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ARDX" }, { "asset": "ARDX", "currency": "USDT", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ARDX" }, { "asset": "TUDA", "currency": "BTC", "min_size": "234.78260870", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TUDA" }, { "asset": "UTK", "currency": "BTC", "min_size": "5.59006210", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UTK" }, { "asset": "PXL", "currency": "BTC", "min_size": "32.53012050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PXL" }, { "asset": "AKRO", "currency": "BTC", "min_size": "59.34065930", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AKRO" }, { "asset": "TSHP", "currency": "BTC", "min_size": "117.39130430", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TSHP" }, { "asset": "HEDG", "currency": "BTC", "min_size": "2.04545450", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HEDG" }, { "asset": "MRPH", "currency": "BTC", "min_size": "1.53583620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MRPH" }, { "asset": "HBAR", "currency": "BTC", "min_size": "10.56751470", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HBAR" }, { "asset": "HBAR", "currency": "ETH", "min_size": "10.58558560", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/HBAR" }, { "asset": "HBAR", "currency": "USD", "min_size": "10.66392530", "max_size": "1000000", "increment": "0.00000001", "label": "USD/HBAR" }, { "asset": "HBAR", "currency": "USDT", "min_size": "10.70187310", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/HBAR" }, { "asset": "VET", "currency": "BTC", "min_size": "12.79620850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VET" }, { "asset": "VET", "currency": "USDT", "min_size": "12.94710060", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VET" }, { "asset": "SIX", "currency": "BTC", "min_size": "24.65753420", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SIX" }, { "asset": "WGP", "currency": "BTC", "min_size": "234.78260870", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WGP" }, { "asset": "APM", "currency": "BTC", "min_size": "90.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/APM" }, { "asset": "FLETA", "currency": "BTC", "min_size": "150.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FLETA" }, { "asset": "DCR", "currency": "USD", "min_size": "0.01415550", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DCR" }, { "asset": "HDAC", "currency": "BTC", "min_size": "43.20000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HDAC" }, { "asset": "LINK", "currency": "BTC", "min_size": "0.08161540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LINK" }, { "asset": "EOS", "currency": "USD", "min_size": "0.45027650", "max_size": "1000000", "increment": "0.00000001", "label": "USD/EOS" }, { "asset": "XTZ", "currency": "BTC", "min_size": "0.51968050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XTZ" }, { "asset": "XTZ", "currency": "ETH", "min_size": "0.51815180", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/XTZ" }, { "asset": "XTZ", "currency": "USD", "min_size": "0.52651070", "max_size": "1000000", "increment": "0.00000001", "label": "USD/XTZ" }, { "asset": "XTZ", "currency": "USDT", "min_size": "0.52191800", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XTZ" }, { "asset": "XTP", "currency": "BTC", "min_size": "415.38461540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XTP" }, { "asset": "CTC", "currency": "BTC", "min_size": "0.53417750", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CTC" }, { "asset": "ATOM", "currency": "USD", "min_size": "0.15361140", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ATOM" }, { "asset": "IOTA", "currency": "BTC", "min_size": "1.39932620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IOTA" }, { "asset": "LINK", "currency": "ETH", "min_size": "0.08174270", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/LINK" }, { "asset": "LINK", "currency": "USD", "min_size": "0.08177790", "max_size": "1000000", "increment": "0.00000001", "label": "USD/LINK" }, { "asset": "LINK", "currency": "USDT", "min_size": "0.08268920", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LINK" }, { "asset": "VRA", "currency": "BTC", "min_size": "72.97297300", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VRA" }, { "asset": "ABBC", "currency": "BTC", "min_size": "21.09375000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ABBC" }, { "asset": "FRSP", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FRSP" }, { "asset": "WICC", "currency": "BTC", "min_size": "5.77540110", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WICC" }, { "asset": "WICC", "currency": "USDT", "min_size": "5.93471810", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/WICC" }, { "asset": "NMR", "currency": "USDT", "min_size": "0.04241610", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NMR" }, { "asset": "RVN", "currency": "USD", "min_size": "16.30959440", "max_size": "1000000", "increment": "0.00000001", "label": "USD/RVN" }, { "asset": "DAI", "currency": "USD", "min_size": "2.99102690", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DAI" }, { "asset": "VANY", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VANY" }, { "asset": "BOA", "currency": "BTC", "min_size": "8.83797050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BOA" }, { "asset": "CPC", "currency": "BTC", "min_size": "138.46153850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CPC" }, { "asset": "CKB", "currency": "BTC", "min_size": "120.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CKB" }, { "asset": "CKB", "currency": "USDT", "min_size": "121.98905600", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CKB" }, { "asset": "MOF", "currency": "BTC", "min_size": "6.67490730", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MOF" }, { "asset": "MOF", "currency": "USDT", "min_size": "6.75675160", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MOF" }, { "asset": "WAXP", "currency": "USD", "min_size": "14.79503330", "max_size": "1000000", "increment": "0.00000001", "label": "USD/WAXP" }, { "asset": "WAXP", "currency": "USDT", "min_size": "15.06888060", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/WAXP" }, { "asset": "UPT", "currency": "BTC", "min_size": "675.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPT" }, { "asset": "UPUSD", "currency": "BTC", "min_size": "3.34987590", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPUSD" }, { "asset": "UPEUR", "currency": "BTC", "min_size": "3.01844610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPEUR" }, { "asset": "CVT", "currency": "BTC", "min_size": "11.44067800", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CVT" }, { "asset": "HBD", "currency": "BTC", "min_size": "1.99041650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HBD" }, { "asset": "HIVE", "currency": "BTC", "min_size": "5.64263320", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HIVE" }, { "asset": "CRO", "currency": "USDT", "min_size": "15.43606900", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CRO" }, { "asset": "SXP", "currency": "BTC", "min_size": "0.81215220", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SXP" }, { "asset": "ELAMA", "currency": "BTC", "min_size": "125.58139540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ELAMA" }, { "asset": "STC", "currency": "BTC", "min_size": "40.90909090", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STC" }, { "asset": "IRIS", "currency": "BTC", "min_size": "17.82178220", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IRIS" }, { "asset": "IRIS", "currency": "USDT", "min_size": "17.85820580", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/IRIS" }, { "asset": "BOA", "currency": "USDT", "min_size": "8.12523410", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BOA" }, { "asset": "BTC", "currency": "EUR", "min_size": "0.00044994", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/BTC" }, { "asset": "ETH", "currency": "EUR", "min_size": "0.02330566", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/ETH" }, { "asset": "USDT", "currency": "EUR", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/USDT" }, { "asset": "BSV", "currency": "EUR", "min_size": "0.01954270", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/BSV" }, { "asset": "BCH", "currency": "EUR", "min_size": "0.01407285", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/BCH" }, { "asset": "TRX", "currency": "EUR", "min_size": "21.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/TRX" }, { "asset": "APM", "currency": "USDT", "min_size": "93.72071230", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/APM" }, { "asset": "HXRO", "currency": "USDT", "min_size": "5.04278610", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/HXRO" }, { "asset": "OGN", "currency": "BTC", "min_size": "1.75040520", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OGN" }, { "asset": "OGN", "currency": "ETH", "min_size": "1.72984910", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/OGN" }, { "asset": "ALGO", "currency": "BTC", "min_size": "2.02778820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ALGO" }, { "asset": "OXT", "currency": "BTC", "min_size": "4.41537200", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OXT" }, { "asset": "OXT", "currency": "USDT", "min_size": "4.47681010", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/OXT" }, { "asset": "ICX", "currency": "BTC", "min_size": "1.38426050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ICX" }, { "asset": "USDC", "currency": "BTC", "min_size": "2.98013240", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/USDC" }, { "asset": "USDC", "currency": "ETH", "min_size": "2.99242340", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/USDC" }, { "asset": "USDC", "currency": "USD", "min_size": "2.99982000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/USDC" }, { "asset": "USDC", "currency": "USDT", "min_size": "3.00441650", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/USDC" }, { "asset": "UPUSD", "currency": "USDT", "min_size": "3.86100380", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UPUSD" }, { "asset": "BRZ", "currency": "USDT", "min_size": "16.85677360", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BRZ" }, { "asset": "XUC", "currency": "BTC", "min_size": "5.07042260", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XUC" }, { "asset": "MDT", "currency": "BTC", "min_size": "43.20000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MDT" }, { "asset": "MDT", "currency": "USDT", "min_size": "44.70272690", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MDT" }, { "asset": "REV", "currency": "BTC", "min_size": "234.78260870", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/REV" }, { "asset": "XUC", "currency": "USDT", "min_size": "5.11509930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XUC" }, { "asset": "REV", "currency": "USDT", "min_size": "231.83925810", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/REV" }, { "asset": "UCT", "currency": "BTC", "min_size": "317.64705880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UCT" }, { "asset": "UCT", "currency": "USDT", "min_size": "340.52213390", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UCT" }, { "asset": "YOU", "currency": "BTC", "min_size": "29.18918920", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/YOU" }, { "asset": "HIVE", "currency": "USD", "min_size": "5.58919420", "max_size": "1000000", "increment": "0.00000001", "label": "USD/HIVE" }, { "asset": "HIVE", "currency": "USDT", "min_size": "5.59670170", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/HIVE" }, { "asset": "ENJ", "currency": "USD", "min_size": "1.23046640", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ENJ" }, { "asset": "ENJ", "currency": "ETH", "min_size": "1.22238790", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/ENJ" }, { "asset": "HDAO", "currency": "BTC", "min_size": "142.10526320", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HDAO" }, { "asset": "HDAO", "currency": "USDT", "min_size": "152.20700150", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/HDAO" }, { "asset": "DNA", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DNA" }, { "asset": "DNA", "currency": "USDT", "min_size": "1415.09433960", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DNA" }, { "asset": "SOLVE", "currency": "USDT", "min_size": "11.63737930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SOLVE" }, { "asset": "CNTM", "currency": "BTC", "min_size": "4.96780130", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CNTM" }, { "asset": "LBC", "currency": "USDT", "min_size": "16.19433200", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LBC" }, { "asset": "LOON", "currency": "BTC", "min_size": "59.34065930", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LOON" }, { "asset": "TNC", "currency": "BTC", "min_size": "69.23076920", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TNC" }, { "asset": "LOON", "currency": "USDT", "min_size": "59.55926150", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LOON" }, { "asset": "ALGO", "currency": "USD", "min_size": "2.05479450", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ALGO" }, { "asset": "ALGO", "currency": "USDT", "min_size": "2.07749040", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ALGO" }, { "asset": "UBT", "currency": "BTC", "min_size": "1.54065620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UBT" }, { "asset": "UBT", "currency": "ETH", "min_size": "1.63567390", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/UBT" }, { "asset": "DEP", "currency": "BTC", "min_size": "300.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DEP" }, { "asset": "DEP", "currency": "USDT", "min_size": "294.40628070", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DEP" }, { "asset": "USD", "currency": "EUR", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/USD" }, { "asset": "CELO", "currency": "BTC", "min_size": "0.74719800", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CELO" }, { "asset": "CELO", "currency": "ETH", "min_size": "0.75834590", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CELO" }, { "asset": "CELO", "currency": "USD", "min_size": "0.75037520", "max_size": "1000000", "increment": "0.00000001", "label": "USD/CELO" }, { "asset": "CELO", "currency": "USDT", "min_size": "0.75547720", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CELO" }, { "asset": "CNTM", "currency": "USDT", "min_size": "4.72017240", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CNTM" }, { "asset": "VID", "currency": "BTC", "min_size": "5.44904140", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VID" }, { "asset": "HNS", "currency": "BTC", "min_size": "5.21739130", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/HNS" }, { "asset": "HNS", "currency": "ETH", "min_size": "5.16634910", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/HNS" }, { "asset": "HNS", "currency": "USDT", "min_size": "4.65116280", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/HNS" }, { "asset": "PHNX", "currency": "BTC", "min_size": "14.02597400", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PHNX" }, { "asset": "UTI", "currency": "BTC", "min_size": "1350.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UTI" }, { "asset": "SOLVE", "currency": "USD", "min_size": "11.56069370", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SOLVE" }, { "asset": "4ART", "currency": "BTC", "min_size": "26.47058820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/4ART" }, { "asset": "4ART", "currency": "USDT", "min_size": "26.95659990", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/4ART" }, { "asset": "VLX", "currency": "BTC", "min_size": "18.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VLX" }, { "asset": "VLX", "currency": "USDT", "min_size": "18.40490800", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VLX" }, { "asset": "MET", "currency": "ETH", "min_size": "0.96856630", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/MET" }, { "asset": "TRAC", "currency": "ETH", "min_size": "4.99698760", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/TRAC" }, { "asset": "TRAC", "currency": "USDT", "min_size": "4.86042480", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TRAC" }, { "asset": "ME", "currency": "BTC", "min_size": "216.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ME" }, { "asset": "DAWN", "currency": "BTC", "min_size": "0.57679980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DAWN" }, { "asset": "KDA", "currency": "BTC", "min_size": "3.09633030", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KDA" }, { "asset": "KDA", "currency": "USDT", "min_size": "3.12327570", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KDA" }, { "asset": "BTE", "currency": "BTC", "min_size": "1.79461610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTE" }, { "asset": "BTE", "currency": "USDT", "min_size": "1.73711640", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BTE" }, { "asset": "GXC", "currency": "BTC", "min_size": "2.94599020", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GXC" }, { "asset": "GXC", "currency": "USDT", "min_size": "2.91047380", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GXC" }, { "asset": "LUCY", "currency": "BTC", "min_size": "186.20689660", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LUCY" }, { "asset": "LUCY", "currency": "USDT", "min_size": "183.03843810", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LUCY" }, { "asset": "COMP", "currency": "BTC", "min_size": "0.00673330", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/COMP" }, { "asset": "COMP", "currency": "ETH", "min_size": "0.00676260", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/COMP" }, { "asset": "COMP", "currency": "USD", "min_size": "0.00676780", "max_size": "1000000", "increment": "0.00000001", "label": "USD/COMP" }, { "asset": "COMP", "currency": "USDT", "min_size": "0.00681930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/COMP" }, { "asset": "LUNA", "currency": "USDT", "min_size": "0.21215130", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LUNA" }, { "asset": "KDAG", "currency": "BTC", "min_size": "4.88245930", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KDAG" }, { "asset": "KDAG", "currency": "USDT", "min_size": "4.92182500", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KDAG" }, { "asset": "WBTC", "currency": "BTC", "min_size": "0.00005380", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WBTC" }, { "asset": "WBTC", "currency": "ETH", "min_size": "0.00005630", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/WBTC" }, { "asset": "WBTC", "currency": "USDT", "min_size": "0.00005300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/WBTC" }, { "asset": "DOGE", "currency": "USD", "min_size": "7.78634270", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DOGE" }, { "asset": "DOGE", "currency": "ETH", "min_size": "7.79177720", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/DOGE" }, { "asset": "UQC", "currency": "BTC", "min_size": "0.13161100", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UQC" }, { "asset": "UQC", "currency": "USDT", "min_size": "0.13558100", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UQC" }, { "asset": "ECOC", "currency": "BTC", "min_size": "91.52542370", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ECOC" }, { "asset": "XLM", "currency": "USD", "min_size": "6.01017690", "max_size": "1000000", "increment": "0.00000001", "label": "USD/XLM" }, { "asset": "ECOC", "currency": "USDT", "min_size": "85.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ECOC" }, { "asset": "FOR", "currency": "BTC", "min_size": "31.39534880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FOR" }, { "asset": "CRO", "currency": "ETH", "min_size": "15.35947710", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CRO" }, { "asset": "SKM", "currency": "BTC", "min_size": "385.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SKM" }, { "asset": "SKM", "currency": "USDT", "min_size": "339.36651590", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SKM" }, { "asset": "CRO", "currency": "EUR", "min_size": "20.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/CRO" }, { "asset": "INSTAR", "currency": "BTC", "min_size": "88.52459020", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/INSTAR" }, { "asset": "SUTER", "currency": "BTC", "min_size": "120.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SUTER" }, { "asset": "SUTER", "currency": "USDT", "min_size": "121.06537530", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SUTER" }, { "asset": "CRO", "currency": "USD", "min_size": "15.31471740", "max_size": "1000000", "increment": "0.00000001", "label": "USD/CRO" }, { "asset": "VANY", "currency": "USDT", "min_size": "1785.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VANY" }, { "asset": "SUKU", "currency": "BTC", "min_size": "4.63121780", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SUKU" }, { "asset": "CGT", "currency": "BTC", "min_size": "0.05201360", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CGT" }, { "asset": "CGT", "currency": "USDT", "min_size": "0.05271300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CGT" }, { "asset": "KSM", "currency": "BTC", "min_size": "0.00797900", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KSM" }, { "asset": "KSM", "currency": "ETH", "min_size": "0.00808960", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/KSM" }, { "asset": "KSM", "currency": "USDT", "min_size": "0.00790150", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KSM" }, { "asset": "SUKU", "currency": "USDT", "min_size": "4.56885260", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SUKU" }, { "asset": "CNS", "currency": "BTC", "min_size": "1350.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CNS" }, { "asset": "CNS", "currency": "USDT", "min_size": "1639.34426230", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CNS" }, { "asset": "MFA", "currency": "BTC", "min_size": "131.70731710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MFA" }, { "asset": "MFA", "currency": "USDT", "min_size": "140.38371550", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MFA" }, { "asset": "DOT", "currency": "BTC", "min_size": "0.08448190", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DOT" }, { "asset": "DOT", "currency": "ETH", "min_size": "0.08489360", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/DOT" }, { "asset": "DOT", "currency": "USDT", "min_size": "0.08579270", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DOT" }, { "asset": "DOT", "currency": "USD", "min_size": "0.08521520", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DOT" }, { "asset": "DOT", "currency": "EUR", "min_size": "1.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/DOT" }, { "asset": "SENSO", "currency": "BTC", "min_size": "2.93000540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SENSO" }, { "asset": "SENSO", "currency": "ETH", "min_size": "2.90703670", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SENSO" }, { "asset": "FME", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FME" }, { "asset": "FME", "currency": "USDT", "min_size": "1485.14851490", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/FME" }, { "asset": "INX", "currency": "BTC", "min_size": "675.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/INX" }, { "asset": "INX", "currency": "USDT", "min_size": "600.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/INX" }, { "asset": "FCT2", "currency": "BTC", "min_size": "15.25423730", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FCT2" }, { "asset": "TRYB", "currency": "BTC", "min_size": "25.71428570", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TRYB" }, { "asset": "TRYB", "currency": "USDT", "min_size": "25.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TRYB" }, { "asset": "KLAY", "currency": "BTC", "min_size": "1.20428190", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KLAY" }, { "asset": "KLAY", "currency": "USDT", "min_size": "1.17779620", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KLAY" }, { "asset": "UST", "currency": "BTC", "min_size": "2.96703300", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UST" }, { "asset": "UST", "currency": "USDT", "min_size": "3.00601200", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UST" }, { "asset": "MKR", "currency": "USDT", "min_size": "0.00088000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MKR" }, { "asset": "KLV", "currency": "BTC", "min_size": "37.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KLV" }, { "asset": "KLV", "currency": "USDT", "min_size": "38.51585570", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KLV" }, { "asset": "OXEN", "currency": "BTC", "min_size": "1.87760780", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OXEN" }, { "asset": "OXEN", "currency": "USDT", "min_size": "1.91795010", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/OXEN" }, { "asset": "USDN", "currency": "BTC", "min_size": "3.03370790", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/USDN" }, { "asset": "USDN", "currency": "USDT", "min_size": "3.07660750", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/USDN" }, { "asset": "SDT", "currency": "BTC", "min_size": "2.19423000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SDT" }, { "asset": "SDT", "currency": "USDT", "min_size": "2.09351010", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SDT" }, { "asset": "MATIC", "currency": "BTC", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MATIC" }, { "asset": "MATIC", "currency": "USDT", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MATIC" }, { "asset": "RVC", "currency": "BTC", "min_size": "2700.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RVC" }, { "asset": "RVC", "currency": "USDT", "min_size": "2830.18867930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RVC" }, { "asset": "KRT", "currency": "BTC", "min_size": "2700.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KRT" }, { "asset": "KRT", "currency": "USDT", "min_size": "3896.10389610", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KRT" }, { "asset": "DUCATO", "currency": "BTC", "min_size": "0.13351790", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DUCATO" }, { "asset": "LMCH", "currency": "BTC", "min_size": "415.38461540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/LMCH" }, { "asset": "LMCH", "currency": "USDT", "min_size": "494.23393740", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LMCH" }, { "asset": "GST", "currency": "BTC", "min_size": "3.28267480", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GST" }, { "asset": "GST", "currency": "USDT", "min_size": "3.33333330", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GST" }, { "asset": "ECELL", "currency": "BTC", "min_size": "55.67010310", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ECELL" }, { "asset": "ECELL", "currency": "USDT", "min_size": "56.25351590", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ECELL" }, { "asset": "BWF", "currency": "BTC", "min_size": "245.45454550", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BWF" }, { "asset": "BWF", "currency": "USDT", "min_size": "237.71790810", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BWF" }, { "asset": "UNI", "currency": "BTC", "min_size": "0.09801790", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UNI" }, { "asset": "UNI", "currency": "ETH", "min_size": "0.09873820", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/UNI" }, { "asset": "UNI", "currency": "USD", "min_size": "0.09802320", "max_size": "1000000", "increment": "0.00000001", "label": "USD/UNI" }, { "asset": "UNI", "currency": "USDT", "min_size": "0.09852540", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UNI" }, { "asset": "EXE", "currency": "BTC", "min_size": "490.90909090", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EXE" }, { "asset": "EXE", "currency": "USDT", "min_size": "483.09178740", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/EXE" }, { "asset": "UPXAU", "currency": "BTC", "min_size": "0.00173710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPXAU" }, { "asset": "ETHBULL", "currency": "USD", "min_size": "0.00050000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ETHBULL" }, { "asset": "ADABEAR", "currency": "USDT", "min_size": "300000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ADABEAR" }, { "asset": "ADABULL", "currency": "USDT", "min_size": "0.00017160", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ADABULL" }, { "asset": "ETHBEAR", "currency": "USDT", "min_size": "100000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ETHBEAR" }, { "asset": "ETHBULL", "currency": "USDT", "min_size": "0.00061480", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ETHBULL" }, { "asset": "BEAR", "currency": "USDT", "min_size": "3061.22448980", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BEAR" }, { "asset": "BULL", "currency": "USDT", "min_size": "0.00005500", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BULL" }, { "asset": "ADABEAR", "currency": "USD", "min_size": "300000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ADABEAR" }, { "asset": "ADABULL", "currency": "USD", "min_size": "0.00017140", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ADABULL" }, { "asset": "ETHBEAR", "currency": "USD", "min_size": "150000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ETHBEAR" }, { "asset": "BULL", "currency": "USD", "min_size": "0.00005410", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BULL" }, { "asset": "BEAR", "currency": "USD", "min_size": "3030.30303030", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BEAR" }, { "asset": "DFI", "currency": "BTC", "min_size": "0.88510080", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DFI" }, { "asset": "DFI", "currency": "USDT", "min_size": "0.88867300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DFI" }, { "asset": "FIL", "currency": "BTC", "min_size": "0.01913610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FIL" }, { "asset": "FIL", "currency": "ETH", "min_size": "0.01914850", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/FIL" }, { "asset": "FIL", "currency": "USD", "min_size": "0.01915120", "max_size": "1000000", "increment": "0.00000001", "label": "USD/FIL" }, { "asset": "FIL", "currency": "USDT", "min_size": "0.01909650", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/FIL" }, { "asset": "ELA", "currency": "BTC", "min_size": "0.32494880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ELA" }, { "asset": "ELA", "currency": "USDT", "min_size": "0.32786890", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ELA" }, { "asset": "CUSD", "currency": "BTC", "min_size": "2.97356830", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CUSD" }, { "asset": "CUSD", "currency": "USDT", "min_size": "3.00300300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CUSD" }, { "asset": "CAMP", "currency": "BTC", "min_size": "2700.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CAMP" }, { "asset": "CAMP", "currency": "USDT", "min_size": "2158.27338130", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CAMP" }, { "asset": "QLC", "currency": "BTC", "min_size": "32.53012050", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/QLC" }, { "asset": "QLC", "currency": "USDT", "min_size": "23.70979220", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/QLC" }, { "asset": "KAI", "currency": "BTC", "min_size": "24.65753420", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KAI" }, { "asset": "KAI", "currency": "USDT", "min_size": "24.39024390", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KAI" }, { "asset": "XWC", "currency": "USDT", "min_size": "1.91289930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XWC" }, { "asset": "GLEEC", "currency": "BTC", "min_size": "5.37848610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GLEEC" }, { "asset": "AKN", "currency": "BTC", "min_size": "8.61244020", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AKN" }, { "asset": "AKN", "currency": "USDT", "min_size": "8.61326440", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AKN" }, { "asset": "NVT", "currency": "BTC", "min_size": "38.57142860", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NVT" }, { "asset": "NVT", "currency": "USDT", "min_size": "39.46849100", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NVT" }, { "asset": "LCS", "currency": "USDT", "min_size": "15.37672990", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LCS" }, { "asset": "SHR", "currency": "BTC", "min_size": "40.60150380", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SHR" }, { "asset": "SHR", "currency": "USDT", "min_size": "41.37360360", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SHR" }, { "asset": "UMA", "currency": "BTC", "min_size": "0.10844030", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UMA" }, { "asset": "UMA", "currency": "ETH", "min_size": "0.10919090", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/UMA" }, { "asset": "UMA", "currency": "EUR", "min_size": "0.37500000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/UMA" }, { "asset": "UMA", "currency": "USD", "min_size": "0.10513770", "max_size": "1000000", "increment": "0.00000001", "label": "USD/UMA" }, { "asset": "UMA", "currency": "USDT", "min_size": "0.10759250", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UMA" }, { "asset": "AAVE", "currency": "BTC", "min_size": "0.00837610", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AAVE" }, { "asset": "AAVE", "currency": "ETH", "min_size": "0.00853260", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/AAVE" }, { "asset": "AAVE", "currency": "EUR", "min_size": "0.04730000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/AAVE" }, { "asset": "AAVE", "currency": "USD", "min_size": "0.00857140", "max_size": "1000000", "increment": "0.00000001", "label": "USD/AAVE" }, { "asset": "AAVE", "currency": "USDT", "min_size": "0.00848500", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AAVE" }, { "asset": "BAL", "currency": "BTC", "min_size": "0.05532390", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BAL" }, { "asset": "BAL", "currency": "ETH", "min_size": "0.05423080", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BAL" }, { "asset": "BAL", "currency": "EUR", "min_size": "0.23700000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/BAL" }, { "asset": "BAL", "currency": "USD", "min_size": "0.05657810", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BAL" }, { "asset": "BAL", "currency": "USDT", "min_size": "0.05656320", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BAL" }, { "asset": "REN", "currency": "BTC", "min_size": "3.41555980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/REN" }, { "asset": "REN", "currency": "ETH", "min_size": "3.32916200", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/REN" }, { "asset": "REN", "currency": "EUR", "min_size": "9.40500000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/REN" }, { "asset": "REN", "currency": "USD", "min_size": "3.47959220", "max_size": "1000000", "increment": "0.00000001", "label": "USD/REN" }, { "asset": "REN", "currency": "USDT", "min_size": "3.44431690", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/REN" }, { "asset": "RENBTC", "currency": "BTC", "min_size": "0.00005390", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RENBTC" }, { "asset": "RENBTC", "currency": "ETH", "min_size": "0.00005470", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/RENBTC" }, { "asset": "RENBTC", "currency": "EUR", "min_size": "0.00018500", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/RENBTC" }, { "asset": "RENBTC", "currency": "USD", "min_size": "0.00005420", "max_size": "1000000", "increment": "0.00000001", "label": "USD/RENBTC" }, { "asset": "RENBTC", "currency": "USDT", "min_size": "0.00005430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RENBTC" }, { "asset": "KNC", "currency": "BTC", "min_size": "1.07956820", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KNC" }, { "asset": "KNC", "currency": "ETH", "min_size": "1.08908900", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/KNC" }, { "asset": "KNC", "currency": "EUR", "min_size": "3.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/KNC" }, { "asset": "KNC", "currency": "USD", "min_size": "1.11111110", "max_size": "1000000", "increment": "0.00000001", "label": "USD/KNC" }, { "asset": "KNC", "currency": "USDT", "min_size": "1.11018600", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KNC" }, { "asset": "BAND", "currency": "BTC", "min_size": "0.19145540", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BAND" }, { "asset": "BAND", "currency": "ETH", "min_size": "0.19926060", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BAND" }, { "asset": "BAND", "currency": "EUR", "min_size": "0.51100000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/BAND" }, { "asset": "BAND", "currency": "USD", "min_size": "0.20040080", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BAND" }, { "asset": "BAND", "currency": "USDT", "min_size": "0.18767600", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BAND" }, { "asset": "YFL", "currency": "BTC", "min_size": "0.01257890", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/YFL" }, { "asset": "YFL", "currency": "ETH", "min_size": "0.01190730", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/YFL" }, { "asset": "YFL", "currency": "EUR", "min_size": "0.00590000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/YFL" }, { "asset": "YFL", "currency": "USD", "min_size": "0.01298300", "max_size": "1000000", "increment": "0.00000001", "label": "USD/YFL" }, { "asset": "YFL", "currency": "USDT", "min_size": "0.01071430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/YFL" }, { "asset": "BBC", "currency": "BTC", "min_size": "19.21708190", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BBC" }, { "asset": "BBC", "currency": "USDT", "min_size": "20.14775020", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BBC" }, { "asset": "XRP", "currency": "EUR", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/XRP" }, { "asset": "ADA", "currency": "EUR", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/ADA" }, { "asset": "XLM", "currency": "EUR", "min_size": "16.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/XLM" }, { "asset": "SG", "currency": "USDT", "min_size": "0.76903360", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SG" }, { "asset": "AAPL", "currency": "BTC", "min_size": "0.02194800", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AAPL" }, { "asset": "AAPL", "currency": "USD", "min_size": "0.02222140", "max_size": "1000000", "increment": "0.00000001", "label": "USD/AAPL" }, { "asset": "AAPL", "currency": "USDT", "min_size": "0.02254930", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AAPL" }, { "asset": "AMZN", "currency": "BTC", "min_size": "0.00090330", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AMZN" }, { "asset": "AMZN", "currency": "USD", "min_size": "0.00088170", "max_size": "1000000", "increment": "0.00000001", "label": "USD/AMZN" }, { "asset": "AMZN", "currency": "USDT", "min_size": "0.00087940", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AMZN" }, { "asset": "BABA", "currency": "BTC", "min_size": "0.01215780", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BABA" }, { "asset": "BABA", "currency": "USD", "min_size": "0.01250540", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BABA" }, { "asset": "BABA", "currency": "USDT", "min_size": "0.01268810", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BABA" }, { "asset": "BILI", "currency": "BTC", "min_size": "0.02828880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BILI" }, { "asset": "BILI", "currency": "USD", "min_size": "0.02803740", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BILI" }, { "asset": "BILI", "currency": "USDT", "min_size": "0.02872600", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BILI" }, { "asset": "BNTX", "currency": "BTC", "min_size": "0.01947180", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BNTX" }, { "asset": "BNTX", "currency": "USD", "min_size": "0.01966050", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BNTX" }, { "asset": "BNTX", "currency": "USDT", "min_size": "0.02069020", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BNTX" }, { "asset": "BYND", "currency": "BTC", "min_size": "0.02449760", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BYND" }, { "asset": "BYND", "currency": "USD", "min_size": "0.02162940", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BYND" }, { "asset": "BYND", "currency": "USDT", "min_size": "0.02162940", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BYND" }, { "asset": "FB", "currency": "BTC", "min_size": "0.00956780", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FB" }, { "asset": "FB", "currency": "USD", "min_size": "0.00976030", "max_size": "1000000", "increment": "0.00000001", "label": "USD/FB" }, { "asset": "FB", "currency": "USDT", "min_size": "0.00996380", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/FB" }, { "asset": "GOOGL", "currency": "BTC", "min_size": "0.00129650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GOOGL" }, { "asset": "GOOGL", "currency": "USD", "min_size": "0.00130700", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GOOGL" }, { "asset": "GOOGL", "currency": "USDT", "min_size": "0.00131880", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GOOGL" }, { "asset": "NFLX", "currency": "BTC", "min_size": "0.00528320", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NFLX" }, { "asset": "NFLX", "currency": "USD", "min_size": "0.00546800", "max_size": "1000000", "increment": "0.00000001", "label": "USD/NFLX" }, { "asset": "NFLX", "currency": "USDT", "min_size": "0.00555680", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NFLX" }, { "asset": "PFE", "currency": "BTC", "min_size": "0.07634560", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PFE" }, { "asset": "PFE", "currency": "USD", "min_size": "0.07734350", "max_size": "1000000", "increment": "0.00000001", "label": "USD/PFE" }, { "asset": "PFE", "currency": "USDT", "min_size": "0.07832900", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PFE" }, { "asset": "SPY", "currency": "BTC", "min_size": "0.00715340", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SPY" }, { "asset": "SPY", "currency": "USD", "min_size": "0.00718510", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SPY" }, { "asset": "SPY", "currency": "USDT", "min_size": "0.00726420", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SPY" }, { "asset": "TSLA", "currency": "BTC", "min_size": "0.00426030", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TSLA" }, { "asset": "TSLA", "currency": "USD", "min_size": "0.00421900", "max_size": "1000000", "increment": "0.00000001", "label": "USD/TSLA" }, { "asset": "TSLA", "currency": "USDT", "min_size": "0.00418290", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TSLA" }, { "asset": "ADK", "currency": "BTC", "min_size": "3.23935210", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ADK" }, { "asset": "UPXAU", "currency": "USDT", "min_size": "0.00168800", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UPXAU" }, { "asset": "GNC", "currency": "BTC", "min_size": "78.26086960", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GNC" }, { "asset": "GNC", "currency": "USDT", "min_size": "79.34408890", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GNC" }, { "asset": "CBC", "currency": "USDT", "min_size": "32.70824250", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CBC" }, { "asset": "FIT", "currency": "BTC", "min_size": "675.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FIT" }, { "asset": "ACXT", "currency": "USDT", "min_size": "5.10377680", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ACXT" }, { "asset": "TEA", "currency": "BTC", "min_size": "10.15037600", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TEA" }, { "asset": "TEA", "currency": "USDT", "min_size": "10.45332590", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TEA" }, { "asset": "GRT", "currency": "BTC", "min_size": "1.86399720", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GRT" }, { "asset": "GRT", "currency": "ETH", "min_size": "1.79890540", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/GRT" }, { "asset": "GRT", "currency": "EUR", "min_size": "1.62000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/GRT" }, { "asset": "GRT", "currency": "USD", "min_size": "1.88475360", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GRT" }, { "asset": "GRT", "currency": "USDT", "min_size": "1.88445760", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GRT" }, { "asset": "KOK", "currency": "BTC", "min_size": "5.14285710", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/KOK" }, { "asset": "KOK", "currency": "USDT", "min_size": "5.19480520", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KOK" }, { "asset": "BTCV", "currency": "BTC", "min_size": "0.06203480", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BTCV" }, { "asset": "BTCV", "currency": "USDT", "min_size": "0.06257560", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BTCV" }, { "asset": "SAND", "currency": "USDT", "min_size": "5.75749430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SAND" }, { "asset": "PANDO", "currency": "USDT", "min_size": "0.96930530", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PANDO" }, { "asset": "GOLD", "currency": "USDT", "min_size": "308.00821360", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GOLD" }, { "asset": "MTC", "currency": "BTC", "min_size": "20.37735850", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MTC" }, { "asset": "LBC", "currency": "ETH", "min_size": "15.66666670", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/LBC" }, { "asset": "LBC", "currency": "USD", "min_size": "15.77121230", "max_size": "1000000", "increment": "0.00000001", "label": "USD/LBC" }, { "asset": "OGT", "currency": "BTC", "min_size": "4.91803280", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/OGT" }, { "asset": "OGT", "currency": "USDT", "min_size": "4.97100250", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/OGT" }, { "asset": "MCH", "currency": "USDT", "min_size": "13.92563710", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MCH" }, { "asset": "MYST", "currency": "USDT", "min_size": "6.83869790", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MYST" }, { "asset": "AMC", "currency": "BTC", "min_size": "0.31640010", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AMC" }, { "asset": "AMC", "currency": "USDT", "min_size": "0.31618890", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AMC" }, { "asset": "AMC", "currency": "USD", "min_size": "0.31505990", "max_size": "1000000", "increment": "0.00000001", "label": "USD/AMC" }, { "asset": "GME", "currency": "BTC", "min_size": "0.01766880", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GME" }, { "asset": "GME", "currency": "USDT", "min_size": "0.01804190", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GME" }, { "asset": "GME", "currency": "USD", "min_size": "0.01782430", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GME" }, { "asset": "BB", "currency": "BTC", "min_size": "0.36043250", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BB" }, { "asset": "BB", "currency": "USD", "min_size": "0.34642030", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BB" }, { "asset": "BB", "currency": "USDT", "min_size": "0.35281670", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BB" }, { "asset": "NOK", "currency": "BTC", "min_size": "0.72424890", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NOK" }, { "asset": "NOK", "currency": "USD", "min_size": "0.72957200", "max_size": "1000000", "increment": "0.00000001", "label": "USD/NOK" }, { "asset": "NOK", "currency": "USDT", "min_size": "0.72167430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NOK" }, { "asset": "SLV", "currency": "BTC", "min_size": "0.12325390", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SLV" }, { "asset": "SLV", "currency": "USD", "min_size": "0.12417730", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SLV" }, { "asset": "SLV", "currency": "USDT", "min_size": "0.12573870", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SLV" }, { "asset": "SQ", "currency": "BTC", "min_size": "0.01227740", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SQ" }, { "asset": "SQ", "currency": "USD", "min_size": "0.01229310", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SQ" }, { "asset": "SQ", "currency": "USDT", "min_size": "0.01216910", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SQ" }, { "asset": "MSTR", "currency": "BTC", "min_size": "0.00471690", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MSTR" }, { "asset": "MSTR", "currency": "USD", "min_size": "0.00458840", "max_size": "1000000", "increment": "0.00000001", "label": "USD/MSTR" }, { "asset": "MSTR", "currency": "USDT", "min_size": "0.00474480", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MSTR" }, { "asset": "PHNX", "currency": "USDT", "min_size": "13.86898430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PHNX" }, { "asset": "DOGE", "currency": "EUR", "min_size": "40.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/DOGE" }, { "asset": "RDD", "currency": "USDT", "min_size": "448.43049330", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RDD" }, { "asset": "UPCO2", "currency": "USDT", "min_size": "0.42342980", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UPCO2" }, { "asset": "UPCO2", "currency": "BTC", "min_size": "0.44936340", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UPCO2" }, { "asset": "VRA", "currency": "USDT", "min_size": "74.18397630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VRA" }, { "asset": "PROS", "currency": "USDT", "min_size": "2.85714290", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PROS" }, { "asset": "TFC", "currency": "BTC", "min_size": "5.67226890", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TFC" }, { "asset": "TFC", "currency": "USDT", "min_size": "5.73449300", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TFC" }, { "asset": "DGB", "currency": "EUR", "min_size": "45.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/DGB" }, { "asset": "CBC", "currency": "ETH", "min_size": "28.20000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CBC" }, { "asset": "SMBSWAP", "currency": "BTC", "min_size": "3.05257210", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SMBSWAP" }, { "asset": "SMBSWAP", "currency": "ETH", "min_size": "3.05412960", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SMBSWAP" }, { "asset": "SMBSWAP", "currency": "USDT", "min_size": "3.12503260", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SMBSWAP" }, { "asset": "SMARTCREDIT", "currency": "USDT", "min_size": "0.39261880", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SMARTCREDIT" }, { "asset": "WXBTC", "currency": "USDT", "min_size": "0.55658630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/WXBTC" }, { "asset": "WXBTC", "currency": "BTC", "min_size": "0.54539950", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/WXBTC" }, { "asset": "SBT", "currency": "USDT", "min_size": "94.30996540", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SBT" }, { "asset": "CUSD", "currency": "ETH", "min_size": "2.99483870", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CUSD" }, { "asset": "GLEEC", "currency": "USDT", "min_size": "5.52486190", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GLEEC" }, { "asset": "AGRS", "currency": "USDT", "min_size": "2.46874970", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AGRS" }, { "asset": "BEST", "currency": "USDT", "min_size": "1.29361640", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BEST" }, { "asset": "CUT", "currency": "BTC", "min_size": "8.46394980", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CUT" }, { "asset": "CUT", "currency": "USDT", "min_size": "8.62192850", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CUT" }, { "asset": "SLICE", "currency": "BTC", "min_size": "3.32103320", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SLICE" }, { "asset": "CEL", "currency": "BTC", "min_size": "0.48578630", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CEL" }, { "asset": "CEL", "currency": "USDT", "min_size": "0.49099840", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CEL" }, { "asset": "SLICE", "currency": "USDT", "min_size": "3.44831550", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SLICE" }, { "asset": "IQQ", "currency": "USDT", "min_size": "15.41623850", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/IQQ" }, { "asset": "IQQ", "currency": "BTC", "min_size": "15.34090910", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/IQQ" }, { "asset": "REVV", "currency": "BTC", "min_size": "10.40462430", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/REVV" }, { "asset": "REVV", "currency": "USDT", "min_size": "10.41666670", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/REVV" }, { "asset": "XEM", "currency": "USD", "min_size": "7.79423230", "max_size": "1000000", "increment": "0.00000001", "label": "USD/XEM" }, { "asset": "IOTA", "currency": "USD", "min_size": "1.41442720", "max_size": "1000000", "increment": "0.00000001", "label": "USD/IOTA" }, { "asset": "IOTA", "currency": "USDT", "min_size": "1.41776940", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/IOTA" }, { "asset": "XEM", "currency": "USDT", "min_size": "7.88705730", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XEM" }, { "asset": "UBQ", "currency": "USDT", "min_size": "5.19552490", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UBQ" }, { "asset": "LSK", "currency": "USDT", "min_size": "0.56295740", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/LSK" }, { "asset": "WAVES", "currency": "USDT", "min_size": "0.23940630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/WAVES" }, { "asset": "KMD", "currency": "USDT", "min_size": "1.10091740", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/KMD" }, { "asset": "VAL", "currency": "USDT", "min_size": "0.92364530", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VAL" }, { "asset": "MATIC", "currency": "USD", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/MATIC" }, { "asset": "ROOM", "currency": "BTC", "min_size": "1.92788290", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ROOM" }, { "asset": "ROOM", "currency": "USDT", "min_size": "1.95185430", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ROOM" }, { "asset": "SPI", "currency": "BTC", "min_size": "0.02070920", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SPI" }, { "asset": "SPI", "currency": "USDT", "min_size": "0.02072570", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SPI" }, { "asset": "JOB", "currency": "BTC", "min_size": "1800.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/JOB" }, { "asset": "JOB", "currency": "USDT", "min_size": "1796.40718560", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/JOB" }, { "asset": "GNY", "currency": "BTC", "min_size": "2.59241480", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GNY" }, { "asset": "GAME", "currency": "USDT", "min_size": "11.08975310", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GAME" }, { "asset": "OMG", "currency": "USD", "min_size": "0.37907510", "max_size": "1000000", "increment": "0.00000001", "label": "USD/OMG" }, { "asset": "QTUM", "currency": "USDT", "min_size": "0.16173380", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/QTUM" }, { "asset": "INXT", "currency": "BTC", "min_size": "0.20338220", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/INXT" }, { "asset": "INXT", "currency": "USDT", "min_size": "0.17467250", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/INXT" }, { "asset": "CLT", "currency": "BTC", "min_size": "0.38235500", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CLT" }, { "asset": "CLT", "currency": "USDT", "min_size": "0.37318070", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CLT" }, { "asset": "FOL", "currency": "BTC", "min_size": "2.42043930", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/FOL" }, { "asset": "FOL", "currency": "USDT", "min_size": "2.42387030", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/FOL" }, { "asset": "VIL", "currency": "BTC", "min_size": "0.11441650", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/VIL" }, { "asset": "STRK", "currency": "BTC", "min_size": "0.07500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/STRK" }, { "asset": "STRK", "currency": "USDT", "min_size": "0.07500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/STRK" }, { "asset": "CELO", "currency": "EUR", "min_size": "0.61000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/CELO" }, { "asset": "DFI", "currency": "EUR", "min_size": "0.90000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/DFI" }, { "asset": "UBT", "currency": "EUR", "min_size": "1.75000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/UBT" }, { "asset": "UNI", "currency": "EUR", "min_size": "0.10000000", "max_size": "1000000", "increment": "0.00000001", "label": "EUR/UNI" }, { "asset": "GET", "currency": "USDT", "min_size": "0.54854630", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GET" }, { "asset": "GET", "currency": "BTC", "min_size": "0.55248620", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GET" }, { "asset": "XELS", "currency": "BTC", "min_size": "0.51868220", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XELS" }, { "asset": "XELS", "currency": "USDT", "min_size": "0.52182990", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XELS" }, { "asset": "RFOX", "currency": "BTC", "min_size": "10.77844310", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RFOX" }, { "asset": "RFOX", "currency": "USDT", "min_size": "10.00033340", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RFOX" }, { "asset": "BONDLY", "currency": "BTC", "min_size": "7.40740740", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BONDLY" }, { "asset": "BONDLY", "currency": "USDT", "min_size": "7.61750000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BONDLY" }, { "asset": "COIN", "currency": "USD", "min_size": "0.00923270", "max_size": "1000000", "increment": "0.00000001", "label": "USD/COIN" }, { "asset": "COIN", "currency": "USDT", "min_size": "0.00919500", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/COIN" }, { "asset": "COIN", "currency": "BTC", "min_size": "0.00924460", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/COIN" }, { "asset": "BONDLY", "currency": "ETH", "min_size": "7.13743360", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BONDLY" }, { "asset": "1INCH", "currency": "BTC", "min_size": "0.51194539", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/1INCH" }, { "asset": "1INCH", "currency": "ETH", "min_size": "0.51107325", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/1INCH" }, { "asset": "1INCH", "currency": "USDT", "min_size": "0.51107325", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/1INCH" }, { "asset": "NFTX", "currency": "BTC", "min_size": "0.02021154", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NFTX" }, { "asset": "NFTX", "currency": "ETH", "min_size": "0.02019658", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/NFTX" }, { "asset": "NFTX", "currency": "USDT", "min_size": "0.02021699", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NFTX" }, { "asset": "URQA", "currency": "BTC", "min_size": "0.85000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/URQA" }, { "asset": "URQA", "currency": "USDT", "min_size": "0.85000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/URQA" }, { "asset": "RSV", "currency": "USD", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/RSV" }, { "asset": "RSV", "currency": "USDT", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RSV" }, { "asset": "RSR", "currency": "BTC", "min_size": "37.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RSR" }, { "asset": "RSR", "currency": "USDT", "min_size": "37.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RSR" }, { "asset": "MANA", "currency": "USD", "min_size": "2.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/MANA" }, { "asset": "STEEM", "currency": "USDT", "min_size": "3.17620303", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/STEEM" }, { "asset": "RGT", "currency": "BTC", "min_size": "0.15000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RGT" }, { "asset": "RGT", "currency": "ETH", "min_size": "0.15000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/RGT" }, { "asset": "RGT", "currency": "USDT", "min_size": "0.15000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RGT" }, { "asset": "MONA", "currency": "USDT", "min_size": "1.20000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MONA" }, { "asset": "AVAX", "currency": "BTC", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AVAX" }, { "asset": "AVAX", "currency": "USDT", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AVAX" }, { "asset": "SNX", "currency": "ETH", "min_size": "0.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SNX" }, { "asset": "SNX", "currency": "USDT", "min_size": "0.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SNX" }, { "asset": "XMY", "currency": "USDT", "min_size": "667.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XMY" }, { "asset": "IGNIS", "currency": "USDT", "min_size": "23.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/IGNIS" }, { "asset": "SIG", "currency": "BTC", "min_size": "1.88000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/SIG" }, { "asset": "SIG", "currency": "ETH", "min_size": "1.88000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/SIG" }, { "asset": "SIG", "currency": "USDT", "min_size": "1.88000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SIG" }, { "asset": "AVAX", "currency": "ETH", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/AVAX" }, { "asset": "ABNB", "currency": "BTC", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ABNB" }, { "asset": "ABNB", "currency": "USD", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ABNB" }, { "asset": "ABNB", "currency": "USDT", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ABNB" }, { "asset": "ACB", "currency": "BTC", "min_size": "0.36000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ACB" }, { "asset": "ACB", "currency": "USD", "min_size": "0.36000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ACB" }, { "asset": "ACB", "currency": "USDT", "min_size": "0.36000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ACB" }, { "asset": "AMD", "currency": "BTC", "min_size": "0.03500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AMD" }, { "asset": "AMD", "currency": "USD", "min_size": "0.03500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/AMD" }, { "asset": "AMD", "currency": "USDT", "min_size": "0.03500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AMD" }, { "asset": "APHA", "currency": "BTC", "min_size": "0.20900000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/APHA" }, { "asset": "APHA", "currency": "USD", "min_size": "0.20900000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/APHA" }, { "asset": "APHA", "currency": "USDT", "min_size": "0.20900000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/APHA" }, { "asset": "ARKK", "currency": "BTC", "min_size": "0.02400000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ARKK" }, { "asset": "ARKK", "currency": "USD", "min_size": "0.02400000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ARKK" }, { "asset": "ARKK", "currency": "USDT", "min_size": "0.02400000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ARKK" }, { "asset": "BITW", "currency": "BTC", "min_size": "0.03700000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BITW" }, { "asset": "BITW", "currency": "USD", "min_size": "0.03700000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/BITW" }, { "asset": "BITW", "currency": "USDT", "min_size": "0.03700000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BITW" }, { "asset": "CGC", "currency": "BTC", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CGC" }, { "asset": "CGC", "currency": "USD", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/CGC" }, { "asset": "CGC", "currency": "USDT", "min_size": "0.11000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CGC" }, { "asset": "CRON", "currency": "BTC", "min_size": "0.36500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CRON" }, { "asset": "CRON", "currency": "USD", "min_size": "0.36500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/CRON" }, { "asset": "CRON", "currency": "USDT", "min_size": "0.36500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CRON" }, { "asset": "GDXJ", "currency": "BTC", "min_size": "0.06000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GDXJ" }, { "asset": "GDXJ", "currency": "USD", "min_size": "0.06000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GDXJ" }, { "asset": "GDXJ", "currency": "USDT", "min_size": "0.06000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GDXJ" }, { "asset": "GLD", "currency": "BTC", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GLD" }, { "asset": "GLD", "currency": "USD", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GLD" }, { "asset": "GLD", "currency": "USDT", "min_size": "0.01800000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GLD" }, { "asset": "GLXY", "currency": "BTC", "min_size": "0.09100000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/GLXY" }, { "asset": "GLXY", "currency": "USD", "min_size": "0.09100000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/GLXY" }, { "asset": "GLXY", "currency": "USDT", "min_size": "0.09100000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/GLXY" }, { "asset": "MRNA", "currency": "BTC", "min_size": "0.01700000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/MRNA" }, { "asset": "MRNA", "currency": "USD", "min_size": "0.01700000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/MRNA" }, { "asset": "MRNA", "currency": "USDT", "min_size": "0.01700000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MRNA" }, { "asset": "NIO", "currency": "BTC", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NIO" }, { "asset": "NIO", "currency": "USD", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/NIO" }, { "asset": "NIO", "currency": "USDT", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NIO" }, { "asset": "NVDA", "currency": "BTC", "min_size": "0.00500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/NVDA" }, { "asset": "NVDA", "currency": "USD", "min_size": "0.00500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/NVDA" }, { "asset": "NVDA", "currency": "USDT", "min_size": "0.00500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NVDA" }, { "asset": "PENN", "currency": "BTC", "min_size": "0.03300000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PENN" }, { "asset": "PENN", "currency": "USD", "min_size": "0.03300000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/PENN" }, { "asset": "PENN", "currency": "USDT", "min_size": "0.03300000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PENN" }, { "asset": "PYPL", "currency": "BTC", "min_size": "0.01100000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PYPL" }, { "asset": "PYPL", "currency": "USD", "min_size": "0.01100000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/PYPL" }, { "asset": "PYPL", "currency": "USDT", "min_size": "0.01100000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PYPL" }, { "asset": "TSM", "currency": "BTC", "min_size": "0.02500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TSM" }, { "asset": "TSM", "currency": "USD", "min_size": "0.02500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/TSM" }, { "asset": "TSM", "currency": "USDT", "min_size": "0.02500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TSM" }, { "asset": "TWTR", "currency": "BTC", "min_size": "0.04500000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/TWTR" }, { "asset": "TWTR", "currency": "USD", "min_size": "0.04500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/TWTR" }, { "asset": "TWTR", "currency": "USDT", "min_size": "0.04500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/TWTR" }, { "asset": "UBER", "currency": "BTC", "min_size": "0.05200000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/UBER" }, { "asset": "UBER", "currency": "USD", "min_size": "0.05200000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/UBER" }, { "asset": "UBER", "currency": "USDT", "min_size": "0.05200000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/UBER" }, { "asset": "USO", "currency": "BTC", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/USO" }, { "asset": "USO", "currency": "USD", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/USO" }, { "asset": "USO", "currency": "USDT", "min_size": "0.07100000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/USO" }, { "asset": "ZM", "currency": "BTC", "min_size": "0.00900000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/ZM" }, { "asset": "ZM", "currency": "USD", "min_size": "0.00900000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ZM" }, { "asset": "ZM", "currency": "USDT", "min_size": "0.00900000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ZM" }, { "asset": "MMAON", "currency": "USDT", "min_size": "20.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MMAON" }, { "asset": "MRPH", "currency": "ETH", "min_size": "1.53583620", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/MRPH" }, { "asset": "MRPH", "currency": "USDT", "min_size": "1.53583620", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MRPH" }, { "asset": "XDB", "currency": "BTC", "min_size": "35.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XDB" }, { "asset": "XDB", "currency": "USDT", "min_size": "35.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XDB" }, { "asset": "ZUSD", "currency": "USDT", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ZUSD" }, { "asset": "SYLO", "currency": "USDT", "min_size": "300.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/SYLO" }, { "asset": "XYM", "currency": "USDT", "min_size": "12.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XYM" }, { "asset": "XYM", "currency": "ETH", "min_size": "12.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/XYM" }, { "asset": "XYM", "currency": "BTC", "min_size": "12.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/XYM" }, { "asset": "NDAU", "currency": "USDT", "min_size": "0.12500000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/NDAU" }, { "asset": "MYID", "currency": "USDT", "min_size": "750.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MYID" }, { "asset": "MOGX", "currency": "USDT", "min_size": "230.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/MOGX" }, { "asset": "DAF", "currency": "USDT", "min_size": "30.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DAF" }, { "asset": "LRC", "currency": "USD", "min_size": "5.40000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/LRC" }, { "asset": "ZILD", "currency": "USDT", "min_size": "0.00750000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ZILD" }, { "asset": "PIST", "currency": "USDT", "min_size": "6.67000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PIST" }, { "asset": "DOGEBULL", "currency": "USD", "min_size": "0.00002200", "max_size": "1000000", "increment": "0.00000001", "label": "USD/DOGEBULL" }, { "asset": "DOGEBULL", "currency": "USDT", "min_size": "0.00002200", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DOGEBULL" }, { "asset": "POLC", "currency": "ETH", "min_size": "5.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/POLC" }, { "asset": "POLC", "currency": "USDT", "min_size": "5.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/POLC" }, { "asset": "XDN", "currency": "USDT", "min_size": "380.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XDN" }, { "asset": "CRV", "currency": "BTC", "min_size": "0.83000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CRV" }, { "asset": "CRV", "currency": "ETH", "min_size": "0.83000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/CRV" }, { "asset": "CRV", "currency": "USDT", "min_size": "0.83000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/CRV" }, { "asset": "RAMP", "currency": "BTC", "min_size": "8.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/RAMP" }, { "asset": "RAMP", "currency": "ETH", "min_size": "8.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/RAMP" }, { "asset": "RAMP", "currency": "USDT", "min_size": "5.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/RAMP" }, { "asset": "PUNDIX", "currency": "ETH", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/PUNDIX" }, { "asset": "PUNDIX", "currency": "USDT", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PUNDIX" }, { "asset": "PUNDIX", "currency": "BTC", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PUNDIX" }, { "asset": "JASMY", "currency": "USDT", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/JASMY" }, { "asset": "ROC", "currency": "USDT", "min_size": "7.50000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/ROC" }, { "asset": "BST", "currency": "BTC", "min_size": "6.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/BST" }, { "asset": "BST", "currency": "USDT", "min_size": "6.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BST" }, { "asset": "VVT", "currency": "USDT", "min_size": "22.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/VVT" }, { "asset": "BAX", "currency": "USDT", "min_size": "3000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/BAX" }, { "asset": "PTOY", "currency": "USDT", "min_size": "150.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PTOY" }, { "asset": "STRK", "currency": "USD", "min_size": "0.07500000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/STRK" }, { "asset": "PIST", "currency": "BTC", "min_size": "6.67000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PIST" }, { "asset": "EDG", "currency": "BTC", "min_size": "188.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/EDG" }, { "asset": "EDG", "currency": "USDT", "min_size": "188.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/EDG" }, { "asset": "AKT", "currency": "BTC", "min_size": "1.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/AKT" }, { "asset": "AKT", "currency": "USDT", "min_size": "1.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/AKT" }, { "asset": "MATIC", "currency": "ETH", "min_size": "2.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/MATIC" }, { "asset": "SNX", "currency": "USD", "min_size": "0.25000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/SNX" }, { "asset": "PRT", "currency": "USDT", "min_size": "86.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PRT" }, { "asset": "BAX", "currency": "ETH", "min_size": "3000.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "ETH/BAX" }, { "asset": "CADX", "currency": "BTC", "min_size": "4.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/CADX" }, { "asset": "XEP", "currency": "USDT", "min_size": "1675.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/XEP" }, { "asset": "PPAY", "currency": "USDT", "min_size": "38.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/PPAY" }, { "asset": "PPAY", "currency": "USD", "min_size": "38.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/PPAY" }, { "asset": "PPAY", "currency": "BTC", "min_size": "38.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/PPAY" }, { "asset": "STORJ", "currency": "USD", "min_size": "3.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/STORJ" }, { "asset": "ANT", "currency": "USD", "min_size": "0.70000000", "max_size": "1000000", "increment": "0.00000001", "label": "USD/ANT" }, { "asset": "DACXI", "currency": "BTC", "min_size": "46.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "BTC/DACXI" }, { "asset": "DACXI", "currency": "USDT", "min_size": "46.00000000", "max_size": "1000000", "increment": "0.00000001", "label": "USDT/DACXI" } ] ================================================ FILE: extensions/exchanges/bittrex/update-products.sh ================================================ #!/usr/bin/env node var bittrex = require('node-bittrex-api') var mapping var products = [] function addProduct(base, quote, minSize, altname) { products.push({ asset: quote, currency: base, min_size: minSize, max_size: '1000000', increment: '0.00000001', label: base + '/' + quote }) } bittrex.getmarkets(function (data) { if(typeof data !== 'object') { console.log('bittrex API had an abnormal response, quitting.') process.exit(1) } if('error' in data || !data.success) { console.log(data.error) console.log(data.message) process.exit(1) } else { mapping = data.result mapping = data.result Object.keys(data.result).forEach(function (result) { addProduct(data.result[result].BaseCurrency, data.result[result].MarketCurrency, data.result[result].MinTradeSize.toFixed(8), data.result[result].altname) }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() } }) ================================================ FILE: extensions/exchanges/cexio/exchange.js ================================================ const CEX = require('cexio-api-node') const path = require('path') const n = require('numbro') const minimist = require('minimist') const _ = require('lodash') const debug = require('../../../lib/debug') module.exports = function cexio (conf) { let s = { options: minimist(process.argv) } let so = s.options let public_client, authed_client, ws_client, ws_authed, ws_subscribed, amount_format let ws_trades = [] let orders = {} function publicClient () { if (!public_client) { public_client = new CEX().rest } return public_client } function authedClient () { if (!authed_client) { if (!conf.cexio || !conf.cexio.username || !conf.cexio.key || conf.cexio.key === 'YOUR-API-KEY') { throw new Error('please configure your CEX.IO credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new CEX(conf.cexio.username, conf.cexio.key, conf.cexio.secret).rest } return authed_client } function joinProduct (product_id) { return product_id.split('-')[0] + '/' + product_id.split('-')[1] } function retry (method, args) { debug.msg(('CEX.IO API is down! unable to call ' + method + ', retrying in 10s').red) setTimeout(function () { exchange[method].apply(exchange, args) }, 10000) } function refreshFees(args) { let skew = 5000 // in ms let now = new Date() let nowUTC = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()) let midnightUTC = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()).setHours(24,0,0,0) let countdown = midnightUTC - nowUTC + skew if (debug.on) { let hours = parseInt((countdown/(1000*60*60))%24) let minutes = parseInt((countdown/(1000*60))%60) let seconds = parseInt((countdown/1000)%60) debug.msg('Refreshing fees in ' + hours + ' hours ' + minutes + ' minutes ' + seconds + ' seconds') } setTimeout(function() { exchange['setFees'].apply(exchange, args) }, countdown) } function wsClient() { return new Promise(function(resolve, reject) { if (!ws_client) { if (!conf.cexio || !conf.cexio.key || conf.cexio.key === 'YOUR-API-KEY') { throw new Error('please configure your CEX.IO credentials in ' + path.resolve(__dirname, 'conf.js')) } ws_client = new CEX(conf.cexio.key, conf.cexio.secret).ws ws_client.open() ws_client.on('open', function() { debug.msg('WebSocket connected') ws_client.auth() ws_client.on('auth', function() { debug.msg('WebSocket authenticated') ws_authed = true resolve(ws_client) }) }) ws_client.on('message', function(msg) { switch (msg.e) { case 'disconnecting': debug.msg('WebSocket disconnecting:', msg.reason) break case 'ping': ws_client.send({ e: 'pong' }) // Heartbeat break case 'get-balance': ws_client.emit('balance', msg.data) break case 'ticker': ws_client.emit('ticker', msg.data) break case 'history': ws_client.emit('history', msg.data) break case 'history-update': msg.data.forEach(function(trade) { ws_trades.push({ trade_id: Number(trade[4]), time: Number(trade[1]), size: Number(n(trade[2]).divide(amount_format).format('0.00000000')), price: Number(trade[3]), side: trade[0] }) }) break case 'cancel-order': ws_client.emit('cancelOrder', msg.data) break case 'place-order': ws_client.emit('placeOrder', msg.data) break case 'get-order': ws_client.emit('getOrder', msg.data) break } }) ws_client.on('error', function(err) { console.error('WebSocket error:', err) }) ws_client.on('close', function() { ws_client = null ws_authed = false ws_subscribed = false debug.msg('WebSocket disconnected') }) } else { switch (ws_client.ws.readyState) { case 0: reject('WebSocket connecting') break case 1: if (ws_authed) { resolve(ws_client) } else { reject('WebSocket auth pending') } break case 2: reject('WebSocket closing') break case 3: reject('WebSocket closed') break } } }) } function wsTrades(pair) { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.send({ e: 'subscribe', rooms: [ 'pair-' + pair ] }) client.once('history', function(trades) { resolve(trades) }) }).catch(function(err) { reject(err) }) }) } function wsBalance() { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.getBalance() client.once('balance', function(balance) { if (balance.error) { reject(balance.error) } else { resolve(balance) } }) }).catch(function(err) { reject(err) }) }) } function wsQuote(pair) { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.authTicker(pair) client.once('ticker', function(quote) { if (quote.error) { reject(quote.error) } else { resolve(quote) } }) }).catch(function(err) { reject(err) }) }) } function wsCancelOrder(order_id) { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.cancelOrder(order_id) client.once('cancelOrder', function(order) { if (order.error) { reject(order.error) } else { resolve() } }) }).catch(function(err) { reject(err) }) }) } function wsTrade(order) { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.placeOrder(order.type, order.pair, order.size, order.price) client.once('placeOrder', function(order) { if (order.error) { reject(order.error) } else { resolve(order) } }) }).catch(function(err) { reject(err) }) }) } function wsGetOrder(order_id) { return new Promise(function(resolve, reject) { wsClient().then(function(client) { client.getOrder(order_id) client.once('getOrder', function(order) { if (order.error) { reject(order.error) } else { resolve(order) } }) }).catch(function(err) { reject(err) }) }) } let exchange = { name: 'cexio', historyScan: 'forward', backfillRateLimit: 0, makerFee: 0.16, takerFee: 0.25, dynamicFees: true, makerBuy100Workaround: true, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { let func_args = [].slice.call(arguments) if (so._[2] === 'backfill') { // Backfill using REST let client = publicClient() let pair = joinProduct(opts.product_id) client.trade_history(pair, opts.from, function (err, body) { if (err || (typeof body === 'string' && body.match(/error/))) { debug.msg(('getTrades ' + (err ? err : body)).red) return retry('getTrades', func_args) } let trades = body.map(function (trade) { return { trade_id: Number(trade.tid), time: Number(trade.date) * 1000, size: Number(trade.amount), price: Number(trade.price), side: trade.type } }) const maxTrade = _.maxBy(trades, 'trade_id') if (maxTrade && (maxTrade.trade_id <= opts.from)) { func_args[0].from = func_args[0].from + trades.length return retry('getTrades', func_args) } cb(null, trades) }) } else { // WebSocket once Live if (!ws_subscribed) wsTrades(opts.product_id).then(function(data) { ws_subscribed = true amount_format = opts.product_id.split('-')[0] === 'ETH' ? 1000000 : 100000000 // trade amount is an unformatted integer data.forEach(function(trade) { let t = trade.split(':') ws_trades.push({ trade_id: Number(t[4]), time: Number(t[1]), size: Number(n(t[2]).divide(amount_format).format('0.00000000')), price: Number(t[3]), side: t[0] }) }) }).catch(function(err) { debug.msg(('getTrades ' + err).red) return retry('getTrades', func_args) }) _.remove(ws_trades, function(t) { return t.trade_id <= opts.from }) cb(null, ws_trades) } }, getBalance: function (opts, cb) { let func_args = [].slice.call(arguments) wsBalance().then(function(data) { let ws_balance = { currency: n(data.balance[opts.currency]).format('0.00000000'), asset: n(data.balance[opts.asset]).format('0.00000000'), currency_hold: n(data.obalance[opts.currency]).format('0.00000000'), asset_hold: n(data.obalance[opts.asset]).format('0.00000000') } cb(null, ws_balance) }).catch(function(err) { debug.msg(('getBalance ' + err).red) return retry('getBalance', func_args) }) }, getQuote: function (opts, cb) { let func_args = [].slice.call(arguments) wsQuote(opts.product_id).then(function(data) { let ws_ticker = { ask: data.ask, bid: data.bid } cb(null, ws_ticker) }).catch(function(err) { debug.msg(('getQuote ' + err).red) return retry('getQuote', func_args) }) }, cancelOrder: function (opts, cb) { let func_args = [].slice.call(arguments) wsCancelOrder(opts.order_id).then(function() { cb() }).catch(function(err) { debug.msg(('cancelOrder ' + err).red) if (err !== 'Error: Order not found') return retry('cancelOrder', func_args) }) }, trade: function (action, opts, cb) { let func_args = [].slice.call(arguments) if (opts.order_type === 'taker') { // Looks like WebSocket doesn't support taker/market orders (yet?) delete opts.price delete opts.post_only if (action === 'buy') { opts.size = n(opts.size).multiply(opts.orig_price).value() // CEXIO estimates asset size and uses free currency to performe margin buy } let client = authedClient() client.place_order(joinProduct(opts.product_id), action, opts.size, opts.price, 'market', function (err, body) { if (err || (typeof body === 'string' && body.match(/error/))) { debug.msg(('trade ' + (err ? err : body)).red) if (body === 'error: Error: Place order error: Insufficient funds.') { let order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } else { return retry('trade', func_args) } } else { let order = { id: body.id, status: 'open', price: opts.price, size: opts.size, post_only: !!opts.post_only, created_at: body.time, filled_size: '0', ordertype: 'taker' } orders['~' + body.id] = order cb(null, order) } }) } else { wsTrade({ type: action, pair: opts.product_id, size: opts.size, price: opts.price }).then(function(data) { let order = { id: data.id, status: 'open', price: data.price, size: data.amount, post_only: !!opts.post_only, created_at: data.time, filled_size: data.amount - data.pending, ordertype: 'maker' } orders['~' + data.id] = order cb(null, order) }).catch(function(err) { debug.msg(('trade ' + err).red) return retry('trade', func_args) }) } }, buy: function (opts, cb) { exchange.trade('buy', opts, cb) }, sell: function (opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function (opts, cb) { let func_args = [].slice.call(arguments) let order = orders['~' + opts.order_id] wsGetOrder(opts.order_id).then(function(data) { if (data.status === 'c') { order.status = 'rejected' order.reject_reason = 'canceled' } else if ( data.status === 'd' || data.status === 'cd') { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = n(data.amount).subtract(data.remains).format('0.00000000') } cb(null, order) }).catch(function(err) { debug.msg(('getOrder ' + err).red) return retry('getOrder', func_args) }) }, setFees: function(opts) { let func_args = [].slice.call(arguments) let client = authedClient() client.get_my_fee(function (err, body) { if (err || (typeof body === 'string' && body.match(/error/))) { debug.msg(('setFees ' + (err ? err : body) + ' - using fixed fees!').red) return retry('setFees', func_args) } else { let pair = opts.asset + ':' + opts.currency let makerFee = (parseFloat(body[pair].buyMaker) + parseFloat(body[pair].sellMaker)) / 2 let takerFee = (parseFloat(body[pair].buy) + parseFloat(body[pair].sell)) / 2 if (exchange.makerFee != makerFee) { debug.msg('Maker fee changed: ' + exchange.makerFee + '% -> ' + makerFee + '%') exchange.makerFee = makerFee } if (exchange.takerFee != takerFee) { debug.msg('Taker fee changed: ' + exchange.takerFee + '% -> ' + takerFee + '%') exchange.takerFee = takerFee } } return refreshFees(func_args) }) }, // return the property used for range querying. getCursor: function (trade) { return trade.trade_id } } return exchange } ================================================ FILE: extensions/exchanges/cexio/products.json ================================================ [ { "asset": "BTC", "currency": "USD", "min_size": "0.0004", "max_size": null, "increment": "0.1", "label": "BTC/USD" }, { "asset": "ETH", "currency": "USD", "min_size": "0.003", "max_size": null, "increment": "0.01", "label": "ETH/USD" }, { "asset": "BCH", "currency": "USD", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "BCH/USD" }, { "asset": "DASH", "currency": "USD", "min_size": "0.065", "max_size": null, "increment": "0.01", "label": "DASH/USD" }, { "asset": "LTC", "currency": "USD", "min_size": "0.03", "max_size": null, "increment": "0.01", "label": "LTC/USD" }, { "asset": "XRP", "currency": "USD", "min_size": "11", "max_size": null, "increment": "0.0001", "label": "XRP/USD" }, { "asset": "XLM", "currency": "USD", "min_size": "32", "max_size": null, "increment": "0.01", "label": "XLM/USD" }, { "asset": "OMG", "currency": "USD", "min_size": "1.5", "max_size": null, "increment": "0.01", "label": "OMG/USD" }, { "asset": "MHC", "currency": "USD", "min_size": "650", "max_size": null, "increment": "0.01", "label": "MHC/USD" }, { "asset": "TRX", "currency": "USD", "min_size": "200", "max_size": null, "increment": "0.01", "label": "TRX/USD" }, { "asset": "BTT", "currency": "USD", "min_size": "780", "max_size": null, "increment": "0.01", "label": "BTT/USD" }, { "asset": "ADA", "currency": "USD", "min_size": "3.825136", "max_size": null, "increment": "0.01", "label": "ADA/USD" }, { "asset": "NEO", "currency": "USD", "min_size": "0.14", "max_size": null, "increment": "0.01", "label": "NEO/USD" }, { "asset": "GAS", "currency": "USD", "min_size": "0.8", "max_size": null, "increment": "0.01", "label": "GAS/USD" }, { "asset": "BAT", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BAT/USD" }, { "asset": "ATOM", "currency": "USD", "min_size": "1.2", "max_size": null, "increment": "0.01", "label": "ATOM/USD" }, { "asset": "XTZ", "currency": "USD", "min_size": "2.5", "max_size": null, "increment": "0.01", "label": "XTZ/USD" }, { "asset": "BTC", "currency": "EUR", "min_size": "0.0004", "max_size": null, "increment": "0.1", "label": "BTC/EUR" }, { "asset": "ETH", "currency": "EUR", "min_size": "0.003", "max_size": null, "increment": "0.01", "label": "ETH/EUR" }, { "asset": "BCH", "currency": "EUR", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "BCH/EUR" }, { "asset": "DASH", "currency": "EUR", "min_size": "0.065", "max_size": null, "increment": "0.01", "label": "DASH/EUR" }, { "asset": "XRP", "currency": "EUR", "min_size": "11", "max_size": null, "increment": "0.0001", "label": "XRP/EUR" }, { "asset": "XLM", "currency": "EUR", "min_size": "32", "max_size": null, "increment": "0.01", "label": "XLM/EUR" }, { "asset": "OMG", "currency": "EUR", "min_size": "1.5", "max_size": null, "increment": "0.01", "label": "OMG/EUR" }, { "asset": "MHC", "currency": "EUR", "min_size": "650", "max_size": null, "increment": "0.01", "label": "MHC/EUR" }, { "asset": "TRX", "currency": "EUR", "min_size": "200", "max_size": null, "increment": "0.01", "label": "TRX/EUR" }, { "asset": "BTT", "currency": "EUR", "min_size": "780", "max_size": null, "increment": "0.01", "label": "BTT/EUR" }, { "asset": "LTC", "currency": "EUR", "min_size": "0.08", "max_size": null, "increment": "0.01", "label": "LTC/EUR" }, { "asset": "ADA", "currency": "EUR", "min_size": "3.825136", "max_size": null, "increment": "0.01", "label": "ADA/EUR" }, { "asset": "NEO", "currency": "EUR", "min_size": "0.14", "max_size": null, "increment": "0.01", "label": "NEO/EUR" }, { "asset": "GAS", "currency": "EUR", "min_size": "0.8", "max_size": null, "increment": "0.01", "label": "GAS/EUR" }, { "asset": "BAT", "currency": "EUR", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BAT/EUR" }, { "asset": "ATOM", "currency": "EUR", "min_size": "1.2", "max_size": null, "increment": "0.01", "label": "ATOM/EUR" }, { "asset": "XTZ", "currency": "EUR", "min_size": "2.5", "max_size": null, "increment": "0.01", "label": "XTZ/EUR" }, { "asset": "BTC", "currency": "GBP", "min_size": "0.0004", "max_size": null, "increment": "0.1", "label": "BTC/GBP" }, { "asset": "ETH", "currency": "GBP", "min_size": "0.003", "max_size": null, "increment": "0.01", "label": "ETH/GBP" }, { "asset": "BCH", "currency": "GBP", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "BCH/GBP" }, { "asset": "MHC", "currency": "GBP", "min_size": "650", "max_size": null, "increment": "0.01", "label": "MHC/GBP" }, { "asset": "LTC", "currency": "GBP", "min_size": "0.08", "max_size": null, "increment": "0.01", "label": "LTC/GBP" }, { "asset": "XRP", "currency": "GBP", "min_size": "11", "max_size": null, "increment": "0.0001", "label": "XRP/GBP" }, { "asset": "ADA", "currency": "GBP", "min_size": "3.825136", "max_size": null, "increment": "0.01", "label": "ADA/GBP" }, { "asset": "NEO", "currency": "GBP", "min_size": "0.14", "max_size": null, "increment": "0.01", "label": "NEO/GBP" }, { "asset": "GAS", "currency": "GBP", "min_size": "0.8", "max_size": null, "increment": "0.01", "label": "GAS/GBP" }, { "asset": "ATOM", "currency": "GBP", "min_size": "1.2", "max_size": null, "increment": "0.01", "label": "ATOM/GBP" }, { "asset": "BAT", "currency": "GBP", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BAT/GBP" }, { "asset": "XTZ", "currency": "GBP", "min_size": "2.5", "max_size": null, "increment": "0.01", "label": "XTZ/GBP" }, { "asset": "BTC", "currency": "RUB", "min_size": "0.0004", "max_size": null, "increment": "1", "label": "BTC/RUB" }, { "asset": "ETH", "currency": "BTC", "min_size": "0.003", "max_size": null, "increment": "0.000001", "label": "ETH/BTC" }, { "asset": "BCH", "currency": "BTC", "min_size": "0.02", "max_size": null, "increment": "0.000001", "label": "BCH/BTC" }, { "asset": "DASH", "currency": "BTC", "min_size": "0.065", "max_size": null, "increment": "0.000001", "label": "DASH/BTC" }, { "asset": "LTC", "currency": "BTC", "min_size": "0.08", "max_size": null, "increment": "0.000001", "label": "LTC/BTC" }, { "asset": "XRP", "currency": "BTC", "min_size": "11", "max_size": null, "increment": "0.00000001", "label": "XRP/BTC" }, { "asset": "XLM", "currency": "BTC", "min_size": "32", "max_size": null, "increment": "0.000001", "label": "XLM/BTC" }, { "asset": "OMG", "currency": "BTC", "min_size": "1.5", "max_size": null, "increment": "0.000001", "label": "OMG/BTC" }, { "asset": "GUSD", "currency": "USD", "min_size": "8", "max_size": null, "increment": "0.01", "label": "GUSD/USD" }, { "asset": "ONT", "currency": "USD", "min_size": "12", "max_size": null, "increment": "0.01", "label": "ONT/USD" }, { "asset": "ONG", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "ONG/USD" }, { "asset": "GUSD", "currency": "EUR", "min_size": "8", "max_size": null, "increment": "0.01", "label": "GUSD/EUR" }, { "asset": "ONT", "currency": "EUR", "min_size": "12", "max_size": null, "increment": "0.01", "label": "ONT/EUR" }, { "asset": "ONG", "currency": "EUR", "min_size": "7", "max_size": null, "increment": "0.01", "label": "ONG/EUR" }, { "asset": "MHC", "currency": "BTC", "min_size": "650", "max_size": null, "increment": "0.000001", "label": "MHC/BTC" }, { "asset": "MHC", "currency": "ETH", "min_size": "650", "max_size": null, "increment": "0.01", "label": "MHC/ETH" }, { "asset": "TRX", "currency": "BTC", "min_size": "200", "max_size": null, "increment": "0.000001", "label": "TRX/BTC" }, { "asset": "BTT", "currency": "BTC", "min_size": "780", "max_size": null, "increment": "0.000001", "label": "BTT/BTC" }, { "asset": "ONT", "currency": "BTC", "min_size": "12", "max_size": null, "increment": "0.000001", "label": "ONT/BTC" }, { "asset": "ONG", "currency": "BTC", "min_size": "7", "max_size": null, "increment": "0.000001", "label": "ONG/BTC" }, { "asset": "USDT", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDT/USD" }, { "asset": "USDT", "currency": "EUR", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDT/EUR" }, { "asset": "USDT", "currency": "GBP", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDT/GBP" }, { "asset": "USDT", "currency": "RUB", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDT/RUB" }, { "asset": "BTC", "currency": "USDT", "min_size": "0.0004", "max_size": null, "increment": "0.1", "label": "BTC/USDT" }, { "asset": "BTC", "currency": "USDC", "min_size": "0.0004", "max_size": null, "increment": "0.1", "label": "BTC/USDC" }, { "asset": "ETH", "currency": "USDT", "min_size": "0.003", "max_size": null, "increment": "0.01", "label": "ETH/USDT" }, { "asset": "BCH", "currency": "USDT", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "BCH/USDT" }, { "asset": "LTC", "currency": "USDT", "min_size": "0.08", "max_size": null, "increment": "0.01", "label": "LTC/USDT" }, { "asset": "XRP", "currency": "USDT", "min_size": "11", "max_size": null, "increment": "0.0001", "label": "XRP/USDT" }, { "asset": "XLM", "currency": "USDT", "min_size": "32", "max_size": null, "increment": "0.01", "label": "XLM/USDT" }, { "asset": "OMG", "currency": "USDT", "min_size": "1.5", "max_size": null, "increment": "0.01", "label": "OMG/USDT" }, { "asset": "TRX", "currency": "USDT", "min_size": "200", "max_size": null, "increment": "0.01", "label": "TRX/USDT" }, { "asset": "ONT", "currency": "USDT", "min_size": "12", "max_size": null, "increment": "0.01", "label": "ONT/USDT" }, { "asset": "ONG", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "ONG/USDT" }, { "asset": "ADA", "currency": "USDT", "min_size": "5.26", "max_size": null, "increment": "0.01", "label": "ADA/USDT" }, { "asset": "USDC", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDC/USD" }, { "asset": "WABI", "currency": "USD", "min_size": "29", "max_size": null, "increment": "0.01", "label": "WABI/USD" }, { "asset": "WABI", "currency": "EUR", "min_size": "29", "max_size": null, "increment": "0.01", "label": "WABI/EUR" }, { "asset": "WABI", "currency": "GBP", "min_size": "29", "max_size": null, "increment": "0.01", "label": "WABI/GBP" }, { "asset": "MATIC", "currency": "USD", "min_size": "9", "max_size": null, "increment": "0.01", "label": "MATIC/USD" }, { "asset": "MATIC", "currency": "EUR", "min_size": "9", "max_size": null, "increment": "0.01", "label": "MATIC/EUR" }, { "asset": "MATIC", "currency": "GBP", "min_size": "9", "max_size": null, "increment": "0.01", "label": "MATIC/GBP" }, { "asset": "MATIC", "currency": "USDT", "min_size": "9", "max_size": null, "increment": "0.01", "label": "MATIC/USDT" }, { "asset": "LINK", "currency": "USD", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "LINK/USD" }, { "asset": "LINK", "currency": "EUR", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "LINK/EUR" }, { "asset": "LINK", "currency": "GBP", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "LINK/GBP" }, { "asset": "MKR", "currency": "USD", "min_size": "0.0015", "max_size": null, "increment": "0.01", "label": "MKR/USD" }, { "asset": "ZRX", "currency": "USD", "min_size": "7.5", "max_size": null, "increment": "0.01", "label": "ZRX/USD" }, { "asset": "ZRX", "currency": "USDT", "min_size": "15", "max_size": null, "increment": "0.01", "label": "ZRX/USDT" }, { "asset": "LAMB", "currency": "USD", "min_size": "157", "max_size": null, "increment": "0.01", "label": "LAMB/USD" }, { "asset": "LAMB", "currency": "USDT", "min_size": "157", "max_size": null, "increment": "0.01", "label": "LAMB/USDT" }, { "asset": "HOT", "currency": "USD", "min_size": "400", "max_size": null, "increment": "0.01", "label": "HOT/USD" }, { "asset": "HOT", "currency": "USDT", "min_size": "400", "max_size": null, "increment": "0.01", "label": "HOT/USDT" }, { "asset": "DASH", "currency": "USDT", "min_size": "0.065", "max_size": null, "increment": "0.01", "label": "DASH/USDT" }, { "asset": "NEO", "currency": "USDT", "min_size": "0.14", "max_size": null, "increment": "0.01", "label": "NEO/USDT" }, { "asset": "GAS", "currency": "USDT", "min_size": "0.8", "max_size": null, "increment": "0.01", "label": "GAS/USDT" }, { "asset": "BAT", "currency": "USDT", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BAT/USDT" }, { "asset": "ATOM", "currency": "USDT", "min_size": "1.2", "max_size": null, "increment": "0.01", "label": "ATOM/USDT" }, { "asset": "XTZ", "currency": "USDT", "min_size": "2.5", "max_size": null, "increment": "0.01", "label": "XTZ/USDT" }, { "asset": "GUSD", "currency": "USDT", "min_size": "8", "max_size": null, "increment": "0.01", "label": "GUSD/USDT" }, { "asset": "USDC", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDC/USDT" }, { "asset": "WABI", "currency": "USDT", "min_size": "29", "max_size": null, "increment": "0.01", "label": "WABI/USDT" }, { "asset": "LINK", "currency": "USDT", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "LINK/USDT" }, { "asset": "DOT", "currency": "USD", "min_size": "0.3", "max_size": null, "increment": "0.01", "label": "DOT/USD" }, { "asset": "DOT", "currency": "USDT", "min_size": "0.3", "max_size": null, "increment": "0.01", "label": "DOT/USDT" }, { "asset": "COMP", "currency": "USD", "min_size": "0.06", "max_size": null, "increment": "0.01", "label": "COMP/USD" }, { "asset": "COMP", "currency": "USDT", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "COMP/USDT" }, { "asset": "ZIL", "currency": "USD", "min_size": "21", "max_size": null, "increment": "0.01", "label": "ZIL/USD" }, { "asset": "ZIL", "currency": "USDT", "min_size": "21", "max_size": null, "increment": "0.01", "label": "ZIL/USDT" }, { "asset": "UNI", "currency": "USD", "min_size": "0.3", "max_size": null, "increment": "0.01", "label": "UNI/USD" }, { "asset": "UNI", "currency": "USDT", "min_size": "0.3", "max_size": null, "increment": "0.01", "label": "UNI/USDT" }, { "asset": "UNI", "currency": "ETH", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "UNI/ETH" }, { "asset": "UMA", "currency": "USD", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "UMA/USD" }, { "asset": "UMA", "currency": "USDT", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "UMA/USDT" }, { "asset": "UMA", "currency": "ETH", "min_size": "0.5", "max_size": null, "increment": "0.01", "label": "UMA/ETH" }, { "asset": "YFI", "currency": "USD", "min_size": "0.0002", "max_size": null, "increment": "0.01", "label": "YFI/USD" }, { "asset": "YFI", "currency": "USDT", "min_size": "0.0002", "max_size": null, "increment": "0.01", "label": "YFI/USDT" }, { "asset": "YFI", "currency": "ETH", "min_size": "0.0002", "max_size": null, "increment": "0.01", "label": "YFI/ETH" }, { "asset": "SNX", "currency": "USD", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SNX/USD" }, { "asset": "SNX", "currency": "USDT", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SNX/USDT" }, { "asset": "SNX", "currency": "ETH", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SNX/ETH" }, { "asset": "KNC", "currency": "USD", "min_size": "3.7", "max_size": null, "increment": "0.01", "label": "KNC/USD" }, { "asset": "KNC", "currency": "USDT", "min_size": "3.7", "max_size": null, "increment": "0.01", "label": "KNC/USDT" }, { "asset": "KNC", "currency": "ETH", "min_size": "3.7", "max_size": null, "increment": "0.01", "label": "KNC/ETH" }, { "asset": "BAL", "currency": "USD", "min_size": "0.6", "max_size": null, "increment": "0.01", "label": "BAL/USD" }, { "asset": "BAL", "currency": "USDT", "min_size": "0.6", "max_size": null, "increment": "0.01", "label": "BAL/USDT" }, { "asset": "BAL", "currency": "ETH", "min_size": "0.6", "max_size": null, "increment": "0.01", "label": "BAL/ETH" }, { "asset": "CRV", "currency": "USD", "min_size": "2.3", "max_size": null, "increment": "0.01", "label": "CRV/USD" }, { "asset": "CRV", "currency": "USDT", "min_size": "3", "max_size": null, "increment": "0.01", "label": "CRV/USDT" }, { "asset": "CRV", "currency": "ETH", "min_size": "3", "max_size": null, "increment": "0.01", "label": "CRV/ETH" }, { "asset": "WBTC", "currency": "USDT", "min_size": "0.0002", "max_size": null, "increment": "0.01", "label": "WBTC/USDT" }, { "asset": "WBTC", "currency": "ETH", "min_size": "0.0002", "max_size": null, "increment": "0.01", "label": "WBTC/ETH" }, { "asset": "DAI", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "DAI/USD" }, { "asset": "DAI", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "DAI/USDT" }, { "asset": "DAI", "currency": "ETH", "min_size": "7", "max_size": null, "increment": "0.01", "label": "DAI/ETH" }, { "asset": "TUSD", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "TUSD/USD" }, { "asset": "TUSD", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "TUSD/USDT" }, { "asset": "TUSD", "currency": "ETH", "min_size": "7", "max_size": null, "increment": "0.01", "label": "TUSD/ETH" }, { "asset": "MTA", "currency": "USDT", "min_size": "8", "max_size": null, "increment": "0.01", "label": "MTA/USDT" }, { "asset": "MTA", "currency": "ETH", "min_size": "8", "max_size": null, "increment": "0.01", "label": "MTA/ETH" }, { "asset": "MUSD", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "MUSD/USDT" }, { "asset": "MUSD", "currency": "ETH", "min_size": "7", "max_size": null, "increment": "0.01", "label": "MUSD/ETH" }, { "asset": "SUSHI", "currency": "USD", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SUSHI/USD" }, { "asset": "SUSHI", "currency": "USDT", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SUSHI/USDT" }, { "asset": "SUSHI", "currency": "ETH", "min_size": "0.7", "max_size": null, "increment": "0.01", "label": "SUSHI/ETH" }, { "asset": "CREAM", "currency": "USDT", "min_size": "0.05", "max_size": null, "increment": "0.01", "label": "CREAM/USDT" }, { "asset": "CREAM", "currency": "ETH", "min_size": "0.05", "max_size": null, "increment": "0.01", "label": "CREAM/ETH" }, { "asset": "YFII", "currency": "USD", "min_size": "0.004", "max_size": null, "increment": "0.01", "label": "YFII/USD" }, { "asset": "YFII", "currency": "USDT", "min_size": "0.004", "max_size": null, "increment": "0.01", "label": "YFII/USDT" }, { "asset": "YFII", "currency": "ETH", "min_size": "0.004", "max_size": null, "increment": "0.01", "label": "YFII/ETH" }, { "asset": "BUSD", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BUSD/USD" }, { "asset": "BUSD", "currency": "USDT", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BUSD/USDT" }, { "asset": "BUSD", "currency": "ETH", "min_size": "10", "max_size": null, "increment": "0.01", "label": "BUSD/ETH" }, { "asset": "REN", "currency": "USD", "min_size": "25", "max_size": null, "increment": "0.01", "label": "REN/USD" }, { "asset": "REN", "currency": "USDT", "min_size": "25", "max_size": null, "increment": "0.01", "label": "REN/USDT" }, { "asset": "REN", "currency": "ETH", "min_size": "25", "max_size": null, "increment": "0.01", "label": "REN/ETH" }, { "asset": "BAND", "currency": "USDT", "min_size": "1.5", "max_size": null, "increment": "0.01", "label": "BAND/USDT" }, { "asset": "BAND", "currency": "ETH", "min_size": "1.5", "max_size": null, "increment": "0.01", "label": "BAND/ETH" }, { "asset": "AKRO", "currency": "USDT", "min_size": "298", "max_size": null, "increment": "0.01", "label": "AKRO/USDT" }, { "asset": "BNT", "currency": "USDT", "min_size": "1.7", "max_size": null, "increment": "0.01", "label": "BNT/USDT" }, { "asset": "ZAP", "currency": "USDT", "min_size": "140", "max_size": null, "increment": "0.01", "label": "ZAP/USDT" }, { "asset": "SRM", "currency": "USDT", "min_size": "0.65", "max_size": null, "increment": "0.01", "label": "SRM/USDT" }, { "asset": "ANT", "currency": "USDT", "min_size": "2.5", "max_size": null, "increment": "0.01", "label": "ANT/USDT" }, { "asset": "PAXG", "currency": "USDT", "min_size": "0.004", "max_size": null, "increment": "0.01", "label": "PAXG/USDT" }, { "asset": "OCEAN", "currency": "USDT", "min_size": "16", "max_size": null, "increment": "0.01", "label": "OCEAN/USDT" }, { "asset": "STORJ", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "STORJ/USDT" }, { "asset": "KAVA", "currency": "USDT", "min_size": "1.8", "max_size": null, "increment": "0.01", "label": "KAVA/USDT" }, { "asset": "KSM", "currency": "USDT", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "KSM/USDT" }, { "asset": "AAVE", "currency": "USDT", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "AAVE/USDT" }, { "asset": "REPV2", "currency": "USDT", "min_size": "0.6", "max_size": null, "increment": "0.01", "label": "REPV2/USDT" }, { "asset": "BCHA", "currency": "USDT", "min_size": "0.4", "max_size": null, "increment": "0.01", "label": "BCHA/USDT" }, { "asset": "OCEAN", "currency": "USD", "min_size": "5.5", "max_size": null, "increment": "0.01", "label": "OCEAN/USD" }, { "asset": "SRM", "currency": "USD", "min_size": "1.6", "max_size": null, "increment": "0.01", "label": "SRM/USD" }, { "asset": "KAVA", "currency": "USD", "min_size": "1.8", "max_size": null, "increment": "0.01", "label": "KAVA/USD" }, { "asset": "STORJ", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "STORJ/USD" }, { "asset": "GLM", "currency": "USDT", "min_size": "24", "max_size": null, "increment": "0.01", "label": "GLM/USDT" }, { "asset": "GLM", "currency": "USD", "min_size": "24", "max_size": null, "increment": "0.01", "label": "GLM/USD" }, { "asset": "GZIL", "currency": "USDT", "min_size": "0.05", "max_size": null, "increment": "0.01", "label": "GZIL/USDT" }, { "asset": "GZIL", "currency": "USD", "min_size": "0.05", "max_size": null, "increment": "0.01", "label": "GZIL/USD" }, { "asset": "TON", "currency": "USDT", "min_size": "7", "max_size": null, "increment": "0.01", "label": "TON/USDT" }, { "asset": "TON", "currency": "USD", "min_size": "7", "max_size": null, "increment": "0.01", "label": "TON/USD" }, { "asset": "AWG", "currency": "USD", "min_size": "0.12", "max_size": null, "increment": "0.01", "label": "AWG/USD" }, { "asset": "FUN", "currency": "USD", "min_size": "309", "max_size": null, "increment": "0.01", "label": "FUN/USD" }, { "asset": "UTK", "currency": "USD", "min_size": "25", "max_size": null, "increment": "0.01", "label": "UTK/USD" }, { "asset": "UTK", "currency": "USDT", "min_size": "25", "max_size": null, "increment": "0.01", "label": "UTK/USDT" }, { "asset": "USDC", "currency": "EUR", "min_size": "7", "max_size": null, "increment": "0.01", "label": "USDC/EUR" }, { "asset": "1INCH", "currency": "USD", "min_size": "2.3", "max_size": null, "increment": "0.01", "label": "1INCH/USD" }, { "asset": "RENBTC", "currency": "USD", "min_size": "0.00015", "max_size": null, "increment": "0.01", "label": "RENBTC/USD" }, { "asset": "RSR", "currency": "USD", "min_size": "216", "max_size": null, "increment": "0.01", "label": "RSR/USD" }, { "asset": "MANA", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "MANA/USD" }, { "asset": "LRC", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "LRC/USD" }, { "asset": "DNT", "currency": "USD", "min_size": "20", "max_size": null, "increment": "0.01", "label": "DNT/USD" }, { "asset": "CVC", "currency": "USD", "min_size": "24", "max_size": null, "increment": "0.01", "label": "CVC/USD" }, { "asset": "XSGD", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "XSGD/USD" }, { "asset": "ZWAP", "currency": "USD", "min_size": "0.01", "max_size": null, "increment": "0.01", "label": "ZWAP/USD" }, { "asset": "BNB", "currency": "USD", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "BNB/USD" }, { "asset": "HAPI", "currency": "USD", "min_size": "0.08", "max_size": null, "increment": "0.01", "label": "HAPI/USD" }, { "asset": "AWX", "currency": "USDT", "min_size": "2", "max_size": null, "increment": "0.01", "label": "AWX/USDT" }, { "asset": "COTI", "currency": "USD", "min_size": "15", "max_size": null, "increment": "0.01", "label": "COTI/USD" }, { "asset": "AWS", "currency": "USD", "min_size": "10", "max_size": null, "increment": "0.01", "label": "AWS/USD" }, { "asset": "AAVE", "currency": "USD", "min_size": "0.02", "max_size": null, "increment": "0.01", "label": "AAVE/USD" }, { "asset": "RENBTC", "currency": "BTC", "min_size": "0.000186", "max_size": null, "increment": "0.000001", "label": "RENBTC/BTC" }, { "asset": "WBTC", "currency": "BTC", "min_size": "0.000185", "max_size": null, "increment": "0.000001", "label": "WBTC/BTC" }, { "asset": "TRX", "currency": "GBP", "min_size": "99.051931", "max_size": null, "increment": "0.01", "label": "TRX/GBP" }, { "asset": "ZAP", "currency": "USD", "min_size": "84.797092", "max_size": null, "increment": "0.01", "label": "ZAP/USD" } ] ================================================ FILE: extensions/exchanges/cexio/update-products.sh ================================================ #!/usr/bin/env node const ccxt = require('ccxt') const path = require('path') var client = new ccxt.cex() client.fetchMarkets().then(result => { var products = [] result.forEach(function (product) { var increment = '' if (product.info.symbol1 === 'BTC' && product.info.symbol2 !== 'RUB') { increment = '0.1' } else if (product.info.symbol1 === 'BTC' && product.info.symbol2 === 'RUB') { increment = '1' } else if (product.info.symbol2 === 'BTC' && (product.info.symbol1 === 'XRP' || product.info.symbol1 === 'GHS')) { increment = '0.00000001' } else if (product.info.symbol2 === 'BTC') { increment = '0.000001' } else if (product.info.symbol1 === 'XRP') { increment = '0.0001' } else { increment = '0.01' } products.push({ asset: product.info.symbol1, currency: product.info.symbol2, min_size: product.info.minLotSize.toString(), max_size: product.info.maxLotSize != null ? product.info.maxLotSize.toString() : product.info.maxLotSize, increment: increment, label: product.id }) }) var target = path.resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/gdax/exchange.js ================================================ var Gdax = require('coinbase-pro'), minimist = require('minimist') module.exports = function gdax (conf) { var so = minimist(process.argv) var public_client = {}, authed_client, websocket_client = {}, websocket_cache = {} function publicClient (product_id) { if (!public_client[product_id]) { websocketClient(product_id) public_client[product_id] = new Gdax.PublicClient(conf.gdax.apiURI) } return public_client[product_id] } function websocketClient (product_id) { if (!websocket_client[product_id]) { var auth = null var client_state = {} if(conf.gdax.key && conf.gdax.key !== 'YOUR-API-KEY'){ auth = { key: conf.gdax.key, secret: conf.gdax.b64secret, passphrase: conf.gdax.passphrase } if(conf.gdax.sandbox == true){ conf.gdax.websocketURI = 'wss://ws-feed-public.sandbox.pro.coinbase.com' } } var channels = ['matches', 'ticker'] // subscribe to user channels which need fully auth data if (auth) { channels.push('user') } websocket_client[product_id] = new Gdax.WebsocketClient([product_id], conf.gdax.websocketURI, auth, {channels}) // initialize a cache for the websocket connection websocket_cache[product_id] = { trades: [], trade_ids: [], orders: {}, ticker: {} } websocket_client[product_id].on('open', () => { if (so.debug) { console.log('websocket connection to ' + product_id + ' opened') } }) websocket_client[product_id].on('message', (message) => { // all messages with user_id are related to trades for current authenticated user if(message.user_id){ if (so.debug) { console.log('websocket user channel income', message) } switch (message.type) { case 'open': handleOrderOpen(message, product_id) break case 'done': handleOrderDone(message, product_id) break case 'change': handleOrderChange(message, product_id) break case 'match': handleOrderMatch(message, product_id) break default: break } } switch (message.type) { case 'open': break case 'done': break case 'change': break case 'match': handleTrade(message, product_id) break case 'ticker': handleTicker(message, product_id) break default: break } }) websocket_client[product_id].on('error', (err) => { client_state.errored = true if (so.debug) { console.error('websocket error: ', err, 'restarting websocket connection') } websocket_client[product_id].disconnect() websocket_client[product_id] = null websocket_cache[product_id] = null websocketClient(product_id) }) websocket_client[product_id].on('close', () => { if (client_state.errored){ client_state.errored = false return } if (so.debug) { console.error('websocket connection to '+product_id+' closed, attempting reconnect') } websocket_client[product_id] = null websocket_client[product_id] = websocketClient(product_id) }) } return websocket_client[product_id] } function authedClient () { if (!authed_client) { if (!conf.gdax || !conf.gdax.key || conf.gdax.key === 'YOUR-API-KEY') { throw new Error('please configure your GDAX credentials in conf.js') } if (conf.gdax.sandbox === true) { conf.gdax.apiURI = 'https://api-public.sandbox.pro.coinbase.com' } authed_client = new Gdax.AuthenticatedClient(conf.gdax.key, conf.gdax.b64secret, conf.gdax.passphrase, conf.gdax.apiURI) } return authed_client } function statusErr (resp, body) { if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body return err } } function retry (method, args, err) { if (method !== 'getTrades') { console.error(('\nGDAX API is down! unable to call ' + method + ', retrying in 10s').red) if (err) console.error(err) console.error(args.slice(0, -1)) } setTimeout(function () { exchange[method].apply(exchange, args) }, 10000) } function handleOrderOpen(update, product_id) { websocket_cache[product_id].orders['~'+update.order_id] = { id: update.order_id, price: update.price, size: update.remaining_size, product_id: update.product_id, side: update.side, status: 'open', settled: false, filled_size: 0 } } function handleOrderDone(update, product_id) { let cached_order = websocket_cache[product_id].orders['~'+update.order_id] if(cached_order){ /* order canceled by user or on platform: which must be retried see "reason": { type: 'done', side: 'sell', order_id: 'xxxx', reason: 'canceled', product_id: 'LTC-EUR', price: '142.33000000', remaining_size: '1.24390150', sequence: 1337, user_id: '5a2aeXXX', profile_id: 'xxx', time: '2018-03-09T16:28:49.293000Z' } complete order response; no further action: { type: 'done', side: 'sell', order_id: 'xxxx', reason: 'filled', product_id: 'LTC-EUR', price: '142.81000000', remaining_size: '0.00000000', sequence: 1337, user_id: '5a2aeXXX', profile_id: 'xxx', time: '2018-03-09T16:56:39.352000Z' } */ // get order "reason": // - "canceled" by user or platform // - "filled" order successfully placed and filled let reason = update.reason cached_order.status = 'done' // "canceled" is not a success order instead it must be retried // force zenbot a order retry; see "engine.js" for possible retry conditions if (reason && reason == 'canceled') { cached_order.status = 'rejected' cached_order.reject_reason = 'post only' } cached_order.done_at = update.time cached_order.done_reason = reason cached_order.settled = true } } function handleOrderChange(update, product_id) { var cached_order = websocket_cache[product_id].orders['~'+update.order_id] if(cached_order && update.new_size){ cached_order.size = update.new_size } } function handleOrderMatch(update, product_id) { var cached_order = websocket_cache[product_id].orders['~'+update.maker_order_id] || websocket_cache[product_id].orders['~'+update.taker_order_id] if(cached_order){ cached_order.price = update.price cached_order.filled_size = (parseFloat(cached_order.filled_size) + update.size).toString() } } function handleTrade(trade, product_id) { var cache = websocket_cache[product_id] cache.trades.push(trade) cache.trade_ids.push(trade.trade_id) } function handleTicker(ticker, product_id) { websocket_cache[product_id].ticker = ticker } var orders = {} var exchange = { name: 'gdax', historyScan: 'backward', makerFee: 0.35, takerFee: 0.35, backfillRateLimit: 335, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient(opts.product_id) var args = {} if (opts.from) { // move cursor into the future args.before = opts.from } else if (opts.to) { // move cursor into the past args.after = opts.to } // check for locally cached trades from the websocket feed var cache = websocket_cache[opts.product_id] var max_trade_id = cache.trade_ids.reduce(function(a, b) { return Math.max(a, b) }, -1) if (opts.from && max_trade_id >= opts.from) { var fromIndex = cache.trades.findIndex((value)=> {return value.trade_id == opts.from}) var newTrades = cache.trades.slice(fromIndex + 1) newTrades = newTrades.map(function (trade) { return { trade_id: trade.trade_id, time: new Date(trade.time).getTime(), size: Number(trade.size), price: Number(trade.price), side: trade.side } }) newTrades.reverse() cb(null, newTrades) // trim cache cache.trades = cache.trades.slice(fromIndex) cache.trade_ids = cache.trade_ids.slice(fromIndex) return } if(so.debug) console.log('getproducttrades call') client.getProductTrades(opts.product_id, args, function (err, resp, body) { if (!err) err = statusErr(resp, body) if (err) return retry('getTrades', func_args, err) var trades = body.map(function (trade) { return { trade_id: trade.trade_id, time: new Date(trade.time).getTime(), size: Number(trade.size), price: Number(trade.price), side: trade.side } }) trades.reverse() cb(null, trades) }) }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (so.debug) { console.log('getaccounts call') } client.getAccounts(function (err, resp, body) { if (!err) err = statusErr(resp, body) if (err) return retry('getBalance', func_args, err) var balance = {asset: 0, currency: 0} body.forEach(function (account) { if (account.currency === opts.currency) { balance.currency = account.balance balance.currency_hold = account.hold } else if (account.currency === opts.asset) { balance.asset = account.balance balance.asset_hold = account.hold } }) cb(null, balance) }) }, getQuote: function (opts, cb) { // check websocket cache first if(websocket_cache[opts.product_id]) { var ticker = websocket_cache[opts.product_id].ticker if(ticker.best_ask && ticker.best_bid){ cb(null, {bid: ticker.best_bid, ask: ticker.best_ask}) return } } var func_args = [].slice.call(arguments) var client = publicClient(opts.product_id) if(so.debug) console.log('getproductticker call') client.getProductTicker(opts.product_id, function (err, resp, body) { if (!err) err = statusErr(resp, body) if (err) return retry('getQuote', func_args, err) if (body.bid || body.ask) cb(null, {bid: body.bid, ask: body.ask}) else cb({code: 'ENOTFOUND', body: opts.product_id + ' has no liquidity to quote'}) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (so.debug) { console.log('cancelorder call') } client.cancelOrder(opts.order_id, function (err, resp, body) { if (body && (body.message === 'Order already done' || body.message === 'order not found')) { return cb() } if (!err) { err = statusErr(resp, body) } if (err) { return retry('cancelOrder', func_args, err) } cb() }) }, buy: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { delete opts.price delete opts.post_only delete opts.cancel_after opts.type = 'market' } else { opts.time_in_force = 'GTT' } delete opts.order_type if (so.debug) { console.log('buy call') } client.buy(opts, function (err, resp, body) { if (body && body.message === 'Insufficient funds') { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } if (!err) { err = statusErr(resp, body) } if (err) { return retry('buy', func_args, err) } orders['~' + body.id] = body cb(null, body) }) }, sell: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { delete opts.price delete opts.post_only delete opts.cancel_after opts.type = 'market' } else { opts.time_in_force = 'GTT' } delete opts.order_type if (so.debug) { console.log('sell call') } client.sell(opts, function (err, resp, body) { if (body && body.message === 'Insufficient funds') { return cb(null, { status: 'rejected', reject_reason: 'balance' }) } if (!err) { err = statusErr(resp, body) } if (err) { return retry('sell', func_args, err) } orders['~' + body.id] = body cb(null, body) }) }, getOrder: function (opts, cb) { if(websocket_cache[opts.product_id] && websocket_cache[opts.product_id].orders['~' + opts.order_id]) { let order_cache = websocket_cache[opts.product_id].orders['~' + opts.order_id] if (so.debug) { console.log('getOrder websocket cache', order_cache) } cb(null, order_cache) return } var func_args = [].slice.call(arguments) var client = authedClient() if (so.debug) { console.log('getorder call') } client.getOrder(opts.order_id, function (err, resp, body) { if (!err && resp.statusCode !== 404) { err = statusErr(resp, body) } if (resp.statusCode === 404) { // order was cancelled. recall from cache body = orders['~' + opts.order_id] body.status = 'done' body.done_reason = 'canceled' } if (err) { return retry('getOrder', func_args, err) } cb(null, body) }) }, // return the property used for range querying. getCursor: function (trade) { return trade.trade_id } } return exchange } ================================================ FILE: extensions/exchanges/gdax/products.json ================================================ [ { "asset": "1INCH", "currency": "BTC", "min_size": "0.1", "max_size": "59000", "increment": "0.0000001", "asset_increment": "0.01", "label": "1INCH/BTC" }, { "asset": "1INCH", "currency": "EUR", "min_size": "0.1", "max_size": "59000", "increment": "0.001", "asset_increment": "0.01", "label": "1INCH/EUR" }, { "asset": "1INCH", "currency": "GBP", "min_size": "0.1", "max_size": "59000", "increment": "0.001", "asset_increment": "0.01", "label": "1INCH/GBP" }, { "asset": "1INCH", "currency": "USD", "min_size": "0.1", "max_size": "59000", "increment": "0.001", "asset_increment": "0.01", "label": "1INCH/USD" }, { "asset": "AAVE", "currency": "BTC", "min_size": "0.01", "max_size": "1200", "increment": "0.00000001", "asset_increment": "0.001", "label": "AAVE/BTC" }, { "asset": "AAVE", "currency": "EUR", "min_size": "0.01", "max_size": "1200", "increment": "0.001", "asset_increment": "0.001", "label": "AAVE/EUR" }, { "asset": "AAVE", "currency": "GBP", "min_size": "0.01", "max_size": "1200", "increment": "0.001", "asset_increment": "0.001", "label": "AAVE/GBP" }, { "asset": "AAVE", "currency": "USD", "min_size": "0.01", "max_size": "1200", "increment": "0.001", "asset_increment": "0.001", "label": "AAVE/USD" }, { "asset": "ADA", "currency": "BTC", "min_size": "1", "max_size": "250000", "increment": "0.00000001", "asset_increment": "0.01", "label": "ADA/BTC" }, { "asset": "ADA", "currency": "ETH", "min_size": "0.1", "max_size": "170000", "increment": "0.000001", "asset_increment": "0.01", "label": "ADA/ETH" }, { "asset": "ADA", "currency": "EUR", "min_size": "1", "max_size": "250000", "increment": "0.0001", "asset_increment": "0.01", "label": "ADA/EUR" }, { "asset": "ADA", "currency": "GBP", "min_size": "1", "max_size": "250000", "increment": "0.0001", "asset_increment": "0.01", "label": "ADA/GBP" }, { "asset": "ADA", "currency": "USD", "min_size": "1", "max_size": "250000", "increment": "0.0001", "asset_increment": "0.01", "label": "ADA/USD" }, { "asset": "ADA", "currency": "USDC", "min_size": "0.1", "max_size": "170000", "increment": "0.001", "asset_increment": "0.01", "label": "ADA/USDC" }, { "asset": "ALGO", "currency": "BTC", "min_size": "1", "max_size": "260000", "increment": "0.00000001", "asset_increment": "1", "label": "ALGO/BTC" }, { "asset": "ALGO", "currency": "EUR", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "1", "label": "ALGO/EUR" }, { "asset": "ALGO", "currency": "GBP", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "1", "label": "ALGO/GBP" }, { "asset": "ALGO", "currency": "USD", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "1", "label": "ALGO/USD" }, { "asset": "AMP", "currency": "USD", "min_size": "10", "max_size": "6800000", "increment": "0.00001", "asset_increment": "1", "label": "AMP/USD" }, { "asset": "ANKR", "currency": "BTC", "min_size": "10", "max_size": "4000000", "increment": "0.00000001", "asset_increment": "1", "label": "ANKR/BTC" }, { "asset": "ANKR", "currency": "EUR", "min_size": "10", "max_size": "4000000", "increment": "0.00001", "asset_increment": "1", "label": "ANKR/EUR" }, { "asset": "ANKR", "currency": "GBP", "min_size": "10", "max_size": "4000000", "increment": "0.00001", "asset_increment": "1", "label": "ANKR/GBP" }, { "asset": "ANKR", "currency": "USD", "min_size": "10", "max_size": "4000000", "increment": "0.00001", "asset_increment": "1", "label": "ANKR/USD" }, { "asset": "ATOM", "currency": "BTC", "min_size": "0.1", "max_size": "25000", "increment": "0.000001", "asset_increment": "0.1", "label": "ATOM/BTC" }, { "asset": "ATOM", "currency": "USD", "min_size": "0.1", "max_size": "25000", "increment": "0.001", "asset_increment": "0.1", "label": "ATOM/USD" }, { "asset": "BAL", "currency": "BTC", "min_size": "0.1", "max_size": "6700", "increment": "0.00000001", "asset_increment": "0.01", "label": "BAL/BTC" }, { "asset": "BAL", "currency": "USD", "min_size": "0.1", "max_size": "6700", "increment": "0.00001", "asset_increment": "0.001", "label": "BAL/USD" }, { "asset": "BAND", "currency": "BTC", "min_size": "0.1", "max_size": "18000", "increment": "0.00000001", "asset_increment": "0.01", "label": "BAND/BTC" }, { "asset": "BAND", "currency": "EUR", "min_size": "0.1", "max_size": "18000", "increment": "0.0001", "asset_increment": "0.01", "label": "BAND/EUR" }, { "asset": "BAND", "currency": "GBP", "min_size": "0.1", "max_size": "18000", "increment": "0.0001", "asset_increment": "0.01", "label": "BAND/GBP" }, { "asset": "BAND", "currency": "USD", "min_size": "0.1", "max_size": "18000", "increment": "0.0001", "asset_increment": "0.01", "label": "BAND/USD" }, { "asset": "BAT", "currency": "BTC", "min_size": "0.1", "max_size": "170000", "increment": "0.0000001", "asset_increment": "0.01", "label": "BAT/BTC" }, { "asset": "BAT", "currency": "ETH", "min_size": "1", "max_size": "300000", "increment": "0.00000001", "asset_increment": "1", "label": "BAT/ETH" }, { "asset": "BAT", "currency": "EUR", "min_size": "0.1", "max_size": "170000", "increment": "0.001", "asset_increment": "0.01", "label": "BAT/EUR" }, { "asset": "BAT", "currency": "USD", "min_size": "0.1", "max_size": "170000", "increment": "0.001", "asset_increment": "0.01", "label": "BAT/USD" }, { "asset": "BAT", "currency": "USDC", "min_size": "1", "max_size": "800000", "increment": "0.000001", "asset_increment": "1", "label": "BAT/USDC" }, { "asset": "BCH", "currency": "BTC", "min_size": "0.01", "max_size": "400", "increment": "0.00001", "asset_increment": "0.00000001", "label": "BCH/BTC" }, { "asset": "BCH", "currency": "EUR", "min_size": "0.01", "max_size": "100", "increment": "0.01", "asset_increment": "0.00000001", "label": "BCH/EUR" }, { "asset": "BCH", "currency": "GBP", "min_size": "0.01", "max_size": "250", "increment": "0.01", "asset_increment": "0.00000001", "label": "BCH/GBP" }, { "asset": "BCH", "currency": "USD", "min_size": "0.01", "max_size": "700", "increment": "0.01", "asset_increment": "0.00000001", "label": "BCH/USD" }, { "asset": "BNT", "currency": "BTC", "min_size": "1", "max_size": "95000", "increment": "0.00000001", "asset_increment": "1", "label": "BNT/BTC" }, { "asset": "BNT", "currency": "EUR", "min_size": "1", "max_size": "95000", "increment": "0.0001", "asset_increment": "0.000001", "label": "BNT/EUR" }, { "asset": "BNT", "currency": "GBP", "min_size": "1", "max_size": "95000", "increment": "0.0001", "asset_increment": "0.000001", "label": "BNT/GBP" }, { "asset": "BNT", "currency": "USD", "min_size": "1", "max_size": "95000", "increment": "0.0001", "asset_increment": "0.000001", "label": "BNT/USD" }, { "asset": "BTC", "currency": "EUR", "min_size": "0.0001", "max_size": "200", "increment": "0.01", "asset_increment": "0.00000001", "label": "BTC/EUR" }, { "asset": "BTC", "currency": "GBP", "min_size": "0.0001", "max_size": "80", "increment": "0.01", "asset_increment": "0.00000001", "label": "BTC/GBP" }, { "asset": "BTC", "currency": "USD", "min_size": "0.0001", "max_size": "280", "increment": "0.01", "asset_increment": "0.00000001", "label": "BTC/USD" }, { "asset": "BTC", "currency": "USDC", "min_size": "0.0001", "max_size": "280", "increment": "0.01", "asset_increment": "0.00000001", "label": "BTC/USDC" }, { "asset": "BTC", "currency": "USDT", "min_size": "0.0001", "max_size": "280", "increment": "0.01", "asset_increment": "0.00000001", "label": "BTC/USDT" }, { "asset": "CGLD", "currency": "BTC", "min_size": "0.1", "max_size": "34000", "increment": "0.00000001", "asset_increment": "0.01", "label": "CGLD/BTC" }, { "asset": "CGLD", "currency": "EUR", "min_size": "0.1", "max_size": "34000", "increment": "0.0001", "asset_increment": "0.01", "label": "CGLD/EUR" }, { "asset": "CGLD", "currency": "GBP", "min_size": "0.1", "max_size": "34000", "increment": "0.0001", "asset_increment": "0.01", "label": "CGLD/GBP" }, { "asset": "CGLD", "currency": "USD", "min_size": "0.1", "max_size": "34000", "increment": "0.0001", "asset_increment": "0.01", "label": "CGLD/USD" }, { "asset": "COMP", "currency": "BTC", "min_size": "0.01", "max_size": "1700", "increment": "0.000001", "asset_increment": "0.001", "label": "COMP/BTC" }, { "asset": "COMP", "currency": "USD", "min_size": "0.01", "max_size": "1700", "increment": "0.01", "asset_increment": "0.001", "label": "COMP/USD" }, { "asset": "CRV", "currency": "BTC", "min_size": "0.5", "max_size": "100000", "increment": "0.0000001", "asset_increment": "0.01", "label": "CRV/BTC" }, { "asset": "CRV", "currency": "EUR", "min_size": "0.5", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "CRV/EUR" }, { "asset": "CRV", "currency": "GBP", "min_size": "0.5", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "CRV/GBP" }, { "asset": "CRV", "currency": "USD", "min_size": "0.5", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "CRV/USD" }, { "asset": "CTSI", "currency": "BTC", "min_size": "1", "max_size": "360000", "increment": "0.0000001", "asset_increment": "0.1", "label": "CTSI/BTC" }, { "asset": "CTSI", "currency": "USD", "min_size": "1", "max_size": "360000", "increment": "0.0001", "asset_increment": "0.1", "label": "CTSI/USD" }, { "asset": "CVC", "currency": "USDC", "min_size": "1", "max_size": "2000000", "increment": "0.000001", "asset_increment": "1", "label": "CVC/USDC" }, { "asset": "DAI", "currency": "USD", "min_size": "1", "max_size": "100000", "increment": "0.000001", "asset_increment": "0.00001", "label": "DAI/USD" }, { "asset": "DAI", "currency": "USDC", "min_size": "1", "max_size": "100000", "increment": "0.000001", "asset_increment": "0.00001", "label": "DAI/USDC" }, { "asset": "DASH", "currency": "BTC", "min_size": "0.01", "max_size": "1500", "increment": "0.00000001", "asset_increment": "0.001", "label": "DASH/BTC" }, { "asset": "DASH", "currency": "USD", "min_size": "0.01", "max_size": "1500", "increment": "0.001", "asset_increment": "0.001", "label": "DASH/USD" }, { "asset": "DNT", "currency": "USDC", "min_size": "1", "max_size": "10000000", "increment": "0.000001", "asset_increment": "1", "label": "DNT/USDC" }, { "asset": "DOGE", "currency": "BTC", "min_size": "1", "max_size": "690000", "increment": "0.0000001", "asset_increment": "0.1", "label": "DOGE/BTC" }, { "asset": "DOGE", "currency": "EUR", "min_size": "1", "max_size": "690000", "increment": "0.0001", "asset_increment": "0.1", "label": "DOGE/EUR" }, { "asset": "DOGE", "currency": "GBP", "min_size": "1", "max_size": "690000", "increment": "0.0001", "asset_increment": "0.1", "label": "DOGE/GBP" }, { "asset": "DOGE", "currency": "USD", "min_size": "1", "max_size": "690000", "increment": "0.0001", "asset_increment": "0.1", "label": "DOGE/USD" }, { "asset": "DOGE", "currency": "USDT", "min_size": "1", "max_size": "690000", "increment": "0.0001", "asset_increment": "0.1", "label": "DOGE/USDT" }, { "asset": "DOT", "currency": "BTC", "min_size": "0.01", "max_size": "10000", "increment": "0.0000001", "asset_increment": "0.001", "label": "DOT/BTC" }, { "asset": "DOT", "currency": "EUR", "min_size": "0.01", "max_size": "10000", "increment": "0.001", "asset_increment": "0.001", "label": "DOT/EUR" }, { "asset": "DOT", "currency": "GBP", "min_size": "0.01", "max_size": "10000", "increment": "0.001", "asset_increment": "0.001", "label": "DOT/GBP" }, { "asset": "DOT", "currency": "USD", "min_size": "0.01", "max_size": "10000", "increment": "0.001", "asset_increment": "0.001", "label": "DOT/USD" }, { "asset": "DOT", "currency": "USDT", "min_size": "0.01", "max_size": "10000", "increment": "0.001", "asset_increment": "0.001", "label": "DOT/USDT" }, { "asset": "ENJ", "currency": "BTC", "min_size": "0.1", "max_size": "97000", "increment": "0.0000001", "asset_increment": "0.01", "label": "ENJ/BTC" }, { "asset": "ENJ", "currency": "USD", "min_size": "0.1", "max_size": "97000", "increment": "0.001", "asset_increment": "0.01", "label": "ENJ/USD" }, { "asset": "EOS", "currency": "BTC", "min_size": "0.1", "max_size": "50000", "increment": "0.000001", "asset_increment": "0.1", "label": "EOS/BTC" }, { "asset": "EOS", "currency": "EUR", "min_size": "0.1", "max_size": "50000", "increment": "0.001", "asset_increment": "0.1", "label": "EOS/EUR" }, { "asset": "EOS", "currency": "USD", "min_size": "0.1", "max_size": "50000", "increment": "0.001", "asset_increment": "0.1", "label": "EOS/USD" }, { "asset": "ETC", "currency": "BTC", "min_size": "0.1", "max_size": "5000", "increment": "0.000001", "asset_increment": "0.00000001", "label": "ETC/BTC" }, { "asset": "ETC", "currency": "EUR", "min_size": "0.1", "max_size": "20000", "increment": "0.001", "asset_increment": "0.00000001", "label": "ETC/EUR" }, { "asset": "ETC", "currency": "GBP", "min_size": "0.1", "max_size": "20000", "increment": "0.001", "asset_increment": "0.00000001", "label": "ETC/GBP" }, { "asset": "ETC", "currency": "USD", "min_size": "0.1", "max_size": "20000", "increment": "0.001", "asset_increment": "0.00000001", "label": "ETC/USD" }, { "asset": "ETH", "currency": "BTC", "min_size": "0.001", "max_size": "2400", "increment": "0.00001", "asset_increment": "0.00000001", "label": "ETH/BTC" }, { "asset": "ETH", "currency": "DAI", "min_size": "0.001", "max_size": "700", "increment": "0.01", "asset_increment": "0.0001", "label": "ETH/DAI" }, { "asset": "ETH", "currency": "EUR", "min_size": "0.001", "max_size": "1600", "increment": "0.01", "asset_increment": "0.00000001", "label": "ETH/EUR" }, { "asset": "ETH", "currency": "GBP", "min_size": "0.001", "max_size": "1400", "increment": "0.01", "asset_increment": "0.00000001", "label": "ETH/GBP" }, { "asset": "ETH", "currency": "USD", "min_size": "0.001", "max_size": "2800", "increment": "0.01", "asset_increment": "0.00000001", "label": "ETH/USD" }, { "asset": "ETH", "currency": "USDC", "min_size": "0.001", "max_size": "2800", "increment": "0.01", "asset_increment": "0.00000001", "label": "ETH/USDC" }, { "asset": "ETH", "currency": "USDT", "min_size": "0.001", "max_size": "2800", "increment": "0.01", "asset_increment": "0.00000001", "label": "ETH/USDT" }, { "asset": "FIL", "currency": "BTC", "min_size": "0.01", "max_size": "3400", "increment": "0.00000001", "asset_increment": "0.001", "label": "FIL/BTC" }, { "asset": "FIL", "currency": "EUR", "min_size": "0.01", "max_size": "3400", "increment": "0.0001", "asset_increment": "0.001", "label": "FIL/EUR" }, { "asset": "FIL", "currency": "GBP", "min_size": "0.01", "max_size": "3400", "increment": "0.0001", "asset_increment": "0.001", "label": "FIL/GBP" }, { "asset": "FIL", "currency": "USD", "min_size": "0.01", "max_size": "3400", "increment": "0.0001", "asset_increment": "0.001", "label": "FIL/USD" }, { "asset": "FORTH", "currency": "BTC", "min_size": "0.01", "max_size": "7200", "increment": "0.0000001", "asset_increment": "0.001", "label": "FORTH/BTC" }, { "asset": "FORTH", "currency": "EUR", "min_size": "0.01", "max_size": "7200", "increment": "0.001", "asset_increment": "0.001", "label": "FORTH/EUR" }, { "asset": "FORTH", "currency": "GBP", "min_size": "0.01", "max_size": "7200", "increment": "0.001", "asset_increment": "0.001", "label": "FORTH/GBP" }, { "asset": "FORTH", "currency": "USD", "min_size": "0.01", "max_size": "7200", "increment": "0.001", "asset_increment": "0.001", "label": "FORTH/USD" }, { "asset": "GNT", "currency": "USDC", "min_size": "1", "max_size": "1500000", "increment": "0.000001", "asset_increment": "1", "label": "GNT/USDC" }, { "asset": "GRT", "currency": "BTC", "min_size": "10", "max_size": "2500000", "increment": "0.00000001", "asset_increment": "0.01", "label": "GRT/BTC" }, { "asset": "GRT", "currency": "EUR", "min_size": "10", "max_size": "2500000", "increment": "0.0001", "asset_increment": "0.01", "label": "GRT/EUR" }, { "asset": "GRT", "currency": "GBP", "min_size": "10", "max_size": "2500000", "increment": "0.0001", "asset_increment": "0.01", "label": "GRT/GBP" }, { "asset": "GRT", "currency": "USD", "min_size": "10", "max_size": "2500000", "increment": "0.0001", "asset_increment": "0.01", "label": "GRT/USD" }, { "asset": "GTC", "currency": "USD", "min_size": "0.1", "max_size": "44000", "increment": "0.001", "asset_increment": "0.01", "label": "GTC/USD" }, { "asset": "ICP", "currency": "BTC", "min_size": "0.001", "max_size": "1300", "increment": "0.0000001", "asset_increment": "0.0001", "label": "ICP/BTC" }, { "asset": "ICP", "currency": "EUR", "min_size": "0.001", "max_size": "1300", "increment": "0.001", "asset_increment": "0.0001", "label": "ICP/EUR" }, { "asset": "ICP", "currency": "GBP", "min_size": "0.001", "max_size": "1300", "increment": "0.001", "asset_increment": "0.0001", "label": "ICP/GBP" }, { "asset": "ICP", "currency": "USD", "min_size": "0.001", "max_size": "1300", "increment": "0.001", "asset_increment": "0.0001", "label": "ICP/USD" }, { "asset": "ICP", "currency": "USDT", "min_size": "0.001", "max_size": "1300", "increment": "0.001", "asset_increment": "0.0001", "label": "ICP/USDT" }, { "asset": "KNC", "currency": "BTC", "min_size": "1", "max_size": "600000", "increment": "0.00000001", "asset_increment": "0.1", "label": "KNC/BTC" }, { "asset": "KNC", "currency": "USD", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "0.1", "label": "KNC/USD" }, { "asset": "LINK", "currency": "BTC", "min_size": "0.1", "max_size": "6500", "increment": "0.00000001", "asset_increment": "0.01", "label": "LINK/BTC" }, { "asset": "LINK", "currency": "ETH", "min_size": "0.1", "max_size": "90000", "increment": "0.00000001", "asset_increment": "0.01", "label": "LINK/ETH" }, { "asset": "LINK", "currency": "EUR", "min_size": "0.1", "max_size": "90000", "increment": "0.00001", "asset_increment": "0.01", "label": "LINK/EUR" }, { "asset": "LINK", "currency": "GBP", "min_size": "0.1", "max_size": "90000", "increment": "0.00001", "asset_increment": "0.01", "label": "LINK/GBP" }, { "asset": "LINK", "currency": "USD", "min_size": "0.1", "max_size": "90000", "increment": "0.00001", "asset_increment": "0.01", "label": "LINK/USD" }, { "asset": "LOOM", "currency": "USDC", "min_size": "1", "max_size": "2500000", "increment": "0.000001", "asset_increment": "1", "label": "LOOM/USDC" }, { "asset": "LRC", "currency": "BTC", "min_size": "1", "max_size": "440000", "increment": "0.00000001", "asset_increment": "1", "label": "LRC/BTC" }, { "asset": "LRC", "currency": "USD", "min_size": "1", "max_size": "560000", "increment": "0.0001", "asset_increment": "0.000001", "label": "LRC/USD" }, { "asset": "LTC", "currency": "BTC", "min_size": "0.01", "max_size": "8000", "increment": "0.000001", "asset_increment": "0.00000001", "label": "LTC/BTC" }, { "asset": "LTC", "currency": "EUR", "min_size": "0.01", "max_size": "1000", "increment": "0.01", "asset_increment": "0.00000001", "label": "LTC/EUR" }, { "asset": "LTC", "currency": "GBP", "min_size": "0.01", "max_size": "1000", "increment": "0.01", "asset_increment": "0.00000001", "label": "LTC/GBP" }, { "asset": "LTC", "currency": "USD", "min_size": "0.01", "max_size": "4000", "increment": "0.01", "asset_increment": "0.00000001", "label": "LTC/USD" }, { "asset": "MANA", "currency": "BTC", "min_size": "0.1", "max_size": "220000", "increment": "0.0000001", "asset_increment": "0.01", "label": "MANA/BTC" }, { "asset": "MANA", "currency": "ETH", "min_size": "0.1", "max_size": "220000", "increment": "0.000001", "asset_increment": "0.01", "label": "MANA/ETH" }, { "asset": "MANA", "currency": "EUR", "min_size": "0.1", "max_size": "220000", "increment": "0.001", "asset_increment": "0.01", "label": "MANA/EUR" }, { "asset": "MANA", "currency": "USD", "min_size": "0.1", "max_size": "220000", "increment": "0.001", "asset_increment": "0.01", "label": "MANA/USD" }, { "asset": "MANA", "currency": "USDC", "min_size": "1", "max_size": "2800000", "increment": "0.000001", "asset_increment": "1", "label": "MANA/USDC" }, { "asset": "MATIC", "currency": "BTC", "min_size": "5", "max_size": "1000000", "increment": "0.00000001", "asset_increment": "0.1", "label": "MATIC/BTC" }, { "asset": "MATIC", "currency": "EUR", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "MATIC/EUR" }, { "asset": "MATIC", "currency": "GBP", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "MATIC/GBP" }, { "asset": "MATIC", "currency": "USD", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "MATIC/USD" }, { "asset": "MIR", "currency": "BTC", "min_size": "0.1", "max_size": "27000", "increment": "0.0000001", "asset_increment": "0.01", "label": "MIR/BTC" }, { "asset": "MIR", "currency": "EUR", "min_size": "0.1", "max_size": "27000", "increment": "0.001", "asset_increment": "0.01", "label": "MIR/EUR" }, { "asset": "MIR", "currency": "GBP", "min_size": "0.1", "max_size": "27000", "increment": "0.001", "asset_increment": "0.01", "label": "MIR/GBP" }, { "asset": "MIR", "currency": "USD", "min_size": "0.1", "max_size": "27000", "increment": "0.001", "asset_increment": "0.01", "label": "MIR/USD" }, { "asset": "MKR", "currency": "BTC", "min_size": "0.001", "max_size": "240", "increment": "0.00001", "asset_increment": "0.000001", "label": "MKR/BTC" }, { "asset": "MKR", "currency": "USD", "min_size": "0.001", "max_size": "240", "increment": "0.0001", "asset_increment": "0.000001", "label": "MKR/USD" }, { "asset": "MLN", "currency": "USD", "min_size": "0.01", "max_size": "3300", "increment": "0.001", "asset_increment": "0.001", "label": "MLN/USD" }, { "asset": "NKN", "currency": "BTC", "min_size": "1", "max_size": "1400000", "increment": "0.0000001", "asset_increment": "0.1", "label": "NKN/BTC" }, { "asset": "NKN", "currency": "USD", "min_size": "1", "max_size": "1400000", "increment": "0.0001", "asset_increment": "0.1", "label": "NKN/USD" }, { "asset": "NMR", "currency": "BTC", "min_size": "0.01", "max_size": "3900", "increment": "0.00000001", "asset_increment": "0.001", "label": "NMR/BTC" }, { "asset": "NMR", "currency": "EUR", "min_size": "0.01", "max_size": "3900", "increment": "0.0001", "asset_increment": "0.001", "label": "NMR/EUR" }, { "asset": "NMR", "currency": "GBP", "min_size": "0.01", "max_size": "3900", "increment": "0.0001", "asset_increment": "0.001", "label": "NMR/GBP" }, { "asset": "NMR", "currency": "USD", "min_size": "0.01", "max_size": "3900", "increment": "0.0001", "asset_increment": "0.001", "label": "NMR/USD" }, { "asset": "NU", "currency": "BTC", "min_size": "10", "max_size": "1300000", "increment": "0.00000001", "asset_increment": "1", "label": "NU/BTC" }, { "asset": "NU", "currency": "EUR", "min_size": "10", "max_size": "1300000", "increment": "0.0001", "asset_increment": "0.000001", "label": "NU/EUR" }, { "asset": "NU", "currency": "GBP", "min_size": "10", "max_size": "1300000", "increment": "0.0001", "asset_increment": "0.000001", "label": "NU/GBP" }, { "asset": "NU", "currency": "USD", "min_size": "10", "max_size": "1300000", "increment": "0.0001", "asset_increment": "0.000001", "label": "NU/USD" }, { "asset": "OGN", "currency": "BTC", "min_size": "0.1", "max_size": "130000", "increment": "0.0000001", "asset_increment": "0.01", "label": "OGN/BTC" }, { "asset": "OGN", "currency": "USD", "min_size": "0.1", "max_size": "130000", "increment": "0.001", "asset_increment": "0.01", "label": "OGN/USD" }, { "asset": "OMG", "currency": "BTC", "min_size": "1", "max_size": "150000", "increment": "0.00000001", "asset_increment": "0.1", "label": "OMG/BTC" }, { "asset": "OMG", "currency": "EUR", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "0.1", "label": "OMG/EUR" }, { "asset": "OMG", "currency": "GBP", "min_size": "1", "max_size": "150000", "increment": "0.0001", "asset_increment": "0.1", "label": "OMG/GBP" }, { "asset": "OMG", "currency": "USD", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "0.1", "label": "OMG/USD" }, { "asset": "OXT", "currency": "USD", "min_size": "1", "max_size": "500000", "increment": "0.0001", "asset_increment": "1", "label": "OXT/USD" }, { "asset": "REN", "currency": "BTC", "min_size": "1", "max_size": "460000", "increment": "0.00000001", "asset_increment": "1", "label": "REN/BTC" }, { "asset": "REN", "currency": "USD", "min_size": "1", "max_size": "460000", "increment": "0.0001", "asset_increment": "0.000001", "label": "REN/USD" }, { "asset": "REP", "currency": "BTC", "min_size": "0.1", "max_size": "5000", "increment": "0.000001", "asset_increment": "0.000001", "label": "REP/BTC" }, { "asset": "REP", "currency": "USD", "min_size": "0.1", "max_size": "5000", "increment": "0.01", "asset_increment": "0.000001", "label": "REP/USD" }, { "asset": "RLC", "currency": "BTC", "min_size": "0.1", "max_size": "93000", "increment": "0.0000001", "asset_increment": "0.01", "label": "RLC/BTC" }, { "asset": "RLC", "currency": "USD", "min_size": "0.1", "max_size": "93000", "increment": "0.001", "asset_increment": "0.01", "label": "RLC/USD" }, { "asset": "SKL", "currency": "BTC", "min_size": "5", "max_size": "1000000", "increment": "0.00000001", "asset_increment": "0.1", "label": "SKL/BTC" }, { "asset": "SKL", "currency": "EUR", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "SKL/EUR" }, { "asset": "SKL", "currency": "GBP", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "SKL/GBP" }, { "asset": "SKL", "currency": "USD", "min_size": "5", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.1", "label": "SKL/USD" }, { "asset": "SNX", "currency": "BTC", "min_size": "0.1", "max_size": "19000", "increment": "0.00000001", "asset_increment": "0.01", "label": "SNX/BTC" }, { "asset": "SNX", "currency": "EUR", "min_size": "0.1", "max_size": "19000", "increment": "0.0001", "asset_increment": "0.001", "label": "SNX/EUR" }, { "asset": "SNX", "currency": "GBP", "min_size": "0.1", "max_size": "19000", "increment": "0.0001", "asset_increment": "0.001", "label": "SNX/GBP" }, { "asset": "SNX", "currency": "USD", "min_size": "0.1", "max_size": "19000", "increment": "0.0001", "asset_increment": "0.001", "label": "SNX/USD" }, { "asset": "STORJ", "currency": "BTC", "min_size": "1", "max_size": "280000", "increment": "0.00000001", "asset_increment": "0.01", "label": "STORJ/BTC" }, { "asset": "STORJ", "currency": "USD", "min_size": "1", "max_size": "280000", "increment": "0.0001", "asset_increment": "0.01", "label": "STORJ/USD" }, { "asset": "SUSHI", "currency": "BTC", "min_size": "0.1", "max_size": "12500", "increment": "0.00000001", "asset_increment": "0.01", "label": "SUSHI/BTC" }, { "asset": "SUSHI", "currency": "ETH", "min_size": "0.1", "max_size": "12500", "increment": "0.000001", "asset_increment": "0.01", "label": "SUSHI/ETH" }, { "asset": "SUSHI", "currency": "EUR", "min_size": "0.1", "max_size": "12500", "increment": "0.001", "asset_increment": "0.01", "label": "SUSHI/EUR" }, { "asset": "SUSHI", "currency": "GBP", "min_size": "0.1", "max_size": "12500", "increment": "0.001", "asset_increment": "0.01", "label": "SUSHI/GBP" }, { "asset": "SUSHI", "currency": "USD", "min_size": "0.1", "max_size": "12500", "increment": "0.001", "asset_increment": "0.01", "label": "SUSHI/USD" }, { "asset": "TRB", "currency": "BTC", "min_size": "0.01", "max_size": "3100", "increment": "0.0000001", "asset_increment": "0.001", "label": "TRB/BTC" }, { "asset": "TRB", "currency": "USD", "min_size": "0.01", "max_size": "3100", "increment": "0.001", "asset_increment": "0.001", "label": "TRB/USD" }, { "asset": "UMA", "currency": "BTC", "min_size": "0.01", "max_size": "4500", "increment": "0.00000001", "asset_increment": "0.001", "label": "UMA/BTC" }, { "asset": "UMA", "currency": "EUR", "min_size": "0.01", "max_size": "4500", "increment": "0.001", "asset_increment": "0.001", "label": "UMA/EUR" }, { "asset": "UMA", "currency": "GBP", "min_size": "0.01", "max_size": "4500", "increment": "0.001", "asset_increment": "0.001", "label": "UMA/GBP" }, { "asset": "UMA", "currency": "USD", "min_size": "0.01", "max_size": "4500", "increment": "0.001", "asset_increment": "0.001", "label": "UMA/USD" }, { "asset": "UNI", "currency": "BTC", "min_size": "0.1", "max_size": "25000", "increment": "0.00000001", "asset_increment": "0.1", "label": "UNI/BTC" }, { "asset": "UNI", "currency": "USD", "min_size": "0.1", "max_size": "200000", "increment": "0.0001", "asset_increment": "0.000001", "label": "UNI/USD" }, { "asset": "USDC", "currency": "EUR", "min_size": "1", "max_size": "250000", "increment": "0.001", "asset_increment": "0.01", "label": "USDC/EUR" }, { "asset": "USDC", "currency": "GBP", "min_size": "1", "max_size": "250000", "increment": "0.001", "asset_increment": "0.01", "label": "USDC/GBP" }, { "asset": "USDT", "currency": "EUR", "min_size": "1", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "USDT/EUR" }, { "asset": "USDT", "currency": "GBP", "min_size": "1", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "USDT/GBP" }, { "asset": "USDT", "currency": "USD", "min_size": "1", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.01", "label": "USDT/USD" }, { "asset": "USDT", "currency": "USDC", "min_size": "1", "max_size": "1000000", "increment": "0.0001", "asset_increment": "0.01", "label": "USDT/USDC" }, { "asset": "WBTC", "currency": "BTC", "min_size": "0.0001", "max_size": "10", "increment": "0.0001", "asset_increment": "0.00000001", "label": "WBTC/BTC" }, { "asset": "WBTC", "currency": "USD", "min_size": "0.0001", "max_size": "10", "increment": "0.01", "asset_increment": "0.00000001", "label": "WBTC/USD" }, { "asset": "XLM", "currency": "BTC", "min_size": "1", "max_size": "600000", "increment": "0.00000001", "asset_increment": "1", "label": "XLM/BTC" }, { "asset": "XLM", "currency": "EUR", "min_size": "1", "max_size": "600000", "increment": "0.000001", "asset_increment": "1", "label": "XLM/EUR" }, { "asset": "XLM", "currency": "USD", "min_size": "1", "max_size": "600000", "increment": "0.000001", "asset_increment": "1", "label": "XLM/USD" }, { "asset": "XTZ", "currency": "BTC", "min_size": "1", "max_size": "100000", "increment": "0.00000001", "asset_increment": "0.01", "label": "XTZ/BTC" }, { "asset": "XTZ", "currency": "EUR", "min_size": "1", "max_size": "100000", "increment": "0.00001", "asset_increment": "0.01", "label": "XTZ/EUR" }, { "asset": "XTZ", "currency": "GBP", "min_size": "1", "max_size": "100000", "increment": "0.00001", "asset_increment": "0.01", "label": "XTZ/GBP" }, { "asset": "XTZ", "currency": "USD", "min_size": "1", "max_size": "100000", "increment": "0.0001", "asset_increment": "0.01", "label": "XTZ/USD" }, { "asset": "YFI", "currency": "BTC", "min_size": "0.00001", "max_size": "4.2", "increment": "0.00001", "asset_increment": "0.000001", "label": "YFI/BTC" }, { "asset": "YFI", "currency": "USD", "min_size": "0.00001", "max_size": "5", "increment": "0.01", "asset_increment": "0.000001", "label": "YFI/USD" }, { "asset": "ZEC", "currency": "BTC", "min_size": "0.01", "max_size": "1500", "increment": "0.000001", "asset_increment": "0.0001", "label": "ZEC/BTC" }, { "asset": "ZEC", "currency": "USD", "min_size": "0.01", "max_size": "1200", "increment": "0.01", "asset_increment": "0.00001", "label": "ZEC/USD" }, { "asset": "ZEC", "currency": "USDC", "min_size": "0.01", "max_size": "5000", "increment": "0.01", "asset_increment": "0.00000001", "label": "ZEC/USDC" }, { "asset": "ZRX", "currency": "BTC", "min_size": "1", "max_size": "600000", "increment": "0.00000001", "asset_increment": "0.00001", "label": "ZRX/BTC" }, { "asset": "ZRX", "currency": "EUR", "min_size": "1", "max_size": "600000", "increment": "0.000001", "asset_increment": "0.00001", "label": "ZRX/EUR" }, { "asset": "ZRX", "currency": "USD", "min_size": "1", "max_size": "600000", "increment": "0.000001", "asset_increment": "0.00001", "label": "ZRX/USD" } ] ================================================ FILE: extensions/exchanges/gdax/test.js ================================================ var Gdax = require('coinbase-pro') var c = require('../../../conf') var client = new Gdax.AuthenticatedClient(c.gdax.key, c.gdax.b64secret, c.gdax.passphrase, c.gdax.apiURI) var order_id = 'd63a349d-0a0e-40f5-8ddb-83f8dc23441a' client.getOrder(order_id, function (err, resp, body) { if (err) console.error(err) else if (resp.statusCode === 404) { console.error('NotFound') } else { console.log(body) } }) ================================================ FILE: extensions/exchanges/gdax/update-products.sh ================================================ #!/usr/bin/env node var request = require('micro-request') request('https://api.pro.coinbase.com/products', {headers: {'User-Agent': 'zenbot/4'}}, function (err, resp, body) { if (err) throw err if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body console.error(err) process.exit(1) } var products = [] body.forEach(function (product) { let regex = /\.0*$|(\.\d*[1-9])0+$/ products.push({ asset: product.base_currency, currency: product.quote_currency, //min_size: product.base_min_size, //max_size: product.base_max_size, //increment: product.quote_increment, //asset_increment: product.base_increment, min_size: Number(product.base_min_size).toFixed(10).replace(regex,'$1'), max_size: Number(product.base_max_size).toFixed(10).replace(regex,'$1'), increment: Number(product.quote_increment).toFixed(10).replace(regex,'$1'), asset_increment: Number(product.base_increment).toFixed(10).replace(/\.0*$|(\.\d*[1-9])0+$/,'$1'), label: product.display_name }) }) products.sort(function(a, b) { var nameA = a.label.toUpperCase(); // ignore upper and lowercase var nameB = b.label.toUpperCase(); // ignore upper and lowercase if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } // names must be equal return 0; }); var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/gemini/.snyk ================================================ # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.14.1 ignore: {} # patches apply the minimum changes required to fix a vulnerability patch: SNYK-JS-LODASH-567746: - gemini-api > lodash: patched: '2020-05-01T00:48:22.572Z' ================================================ FILE: extensions/exchanges/gemini/exchange.js ================================================ var GeminiAPI = require('gemini-api'), path = require('path'), minimist = require('minimist'), // eslint-disable-next-line no-unused-vars colors = require('colors'), n = require('numbro') module.exports = function gemini (conf) { var s = { options: minimist(process.argv) } var so = s.options var public_client, authed_client function publicClient() { if (!public_client) public_client = new GeminiAPI.default({ sandbox: conf.gemini.sandbox || false }) return public_client } function authedClient() { if (!authed_client) { if (!conf.gemini || !conf.gemini.key || !conf.gemini.key === 'YOUR-API-KEY') { throw new Error('please configure your Gemini credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new GeminiAPI.default({ key: conf.gemini.key, secret: conf.gemini.secret, sandbox: conf.gemini.sandbox }) } return authed_client } function joinProduct(product_id) { return (product_id.split('-')[0].toLowerCase() + product_id.split('-')[1]).toLowerCase() } function retry(method, args, error) { if (error.code === 429) { console.error((`\nGemini API rate limit exceeded! unable to call ${method}, aborting`).red) return } if (method !== 'getTrades') { console.error((`\nGemini API is down: (${method}) ${error.message}`).red) console.log(('Retrying in 30 sseconds ...').yellow) } debugOut(error) setTimeout(function() { exchange[method].apply(exchange, args) }, 30000) } function debugOut(msg) { if (so.debug) console.log(msg) } var orders = {} var exchange = { name: 'gemini', historyScan: 'forward', makerFee: 0.10, takerFee: 0.10, getProducts: function() { return require('./products.json') }, getTrades: function(opts, cb) { var func_args = [].slice.call(arguments) var args = { limit_trades: 1000, since: opts.from } var client = publicClient() client.getTradeHistory(joinProduct(opts.product_id), args) .then(body => { var trades = body.filter(t => { return t.type !== 'auction' }).map(function(trade) { return { trade_id: trade.tid, time: trade.timestampms, size: Number(trade.amount), price: Number(trade.price), side: trade.type } }) cb(null, trades) }) .catch(error => retry('getTrades', func_args, error)) }, getBalance: function(opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.getMyAvailableBalances() .then(body => { var asset = body.find(x => x.currency.toLowerCase() === opts.asset.toLowerCase()) var currency = body.find(x => x.currency.toLowerCase() === opts.currency.toLowerCase()) var balance = { asset: n(asset.amount).format('0.00000'), asset_hold: n(asset.amount).subtract(asset.available).format('0.00000'), currency: n(currency.amount).format('0.00'), currency_hold: n(currency.amount).subtract(currency.available).format('0.00') } debugOut('Balance/Hold:') debugOut(` ${currency.currency} (${balance.currency}/${balance.currency_hold})`) debugOut(` ${asset.currency} (${balance.asset}/${balance.asset_hold})`) cb(null, balance) }) .catch(error => retry('getBalance', func_args, error)) }, getQuote: function(opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.getTicker(joinProduct(opts.product_id)) .then(body => { var r = { bid: String(body.bid), ask: String(body.ask) } cb(null, r) }) .catch(error => retry('getQuote', func_args, error)) }, cancelOrder: function(opts, cb) { var func_args = [].slice.call(arguments) var params = { order_id: opts.order_id } debugOut(`Cancelling order ${opts.order_id}`) var client = authedClient() client.cancelOrder(params) .then(cb()) .catch(error => retry('cancelOrder', func_args, error)) }, buy: function(opts, cb) { var params = { symbol: joinProduct(opts.product_id), amount: n(opts.size).format('0.00000'), price: n(opts.price).format('0.00'), side: 'buy', type: 'exchange limit', options: [] } if (opts.order_type === 'taker') { params.options.push('immediate-or-cancel') } else if (opts.post_only) { params.options.push('maker-or-cancel') } debugOut(`Requesting ${opts.order_type} buy for ${opts.size} assets`) var client = authedClient() client.newOrder(params) .then(body => { var order = { id: body.order_id, status: 'open', price: Number(opts.price), size: Number(opts.size), created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type, postonly: !!opts.post_only } if (opts.post_only && body.is_cancelled) { order.status = 'rejected', order.reject_reason = 'post only' } debugOut(` Purchase ID: ${body.id}`) orders['~' + body.order_id] = order cb(null, order) }) .catch(error => cb(error)) }, sell: function(opts, cb) { var params = { symbol: joinProduct(opts.product_id), amount: n(opts.size).format('0.00000'), price: n(opts.price).format('0.00'), side: 'sell', type: 'exchange limit', options: [] } if (opts.order_type === 'taker') { params.options.push('immediate-or-cancel') } else if (opts.post_only) { params.options.push('maker-or-cancel') } debugOut(`Requesting ${opts.order_type} sell for ${opts.size} assets`) var client = authedClient() client.newOrder(params) .then(body => { var order = { id: body.order_id, status: 'open', price: Number(opts.price), size: Number(opts.size), created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type, postonly: !!opts.post_only } if (opts.post_only && body.is_cancelled) { order.status = 'rejected', order.reject_reason = 'post only' } debugOut(` Purchase ID: ${body.id}`) orders['~' + body.order_id] = order cb(null, order) }) .catch(error => cb(error)) }, getOrder: function(opts, cb) { var order = orders['~' + opts.order_id] var params = { order_id: opts.order_id } var client = authedClient() client.getMyOrderStatus(params) .then(body => { if (typeof body !== 'undefined') { if (body.is_cancelled) { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = '0.00000' } else if (!body.is_live) { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = n(body.executed_amount).format('0.00000') order.price = n(body.avg_execution_price).format('0.00') } else { order.filled_size = n(body.executed_amount).format('0.00000') order.price = n(body.avg_execution_price).format('0.00') } } debugOut(`Lookup order ${opts.order_id} status is ${order.status}`) cb(null, order) }) .catch(error => cb(error)) }, // return the property used for range querying. getCursor: function(trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/gemini/package.json ================================================ { "name": "zenbot_gemini", "version": "0.0.1", "description": "Zenbot supporting code for Gemini", "dependencies": { "gemini-api": "^2.0.4", "snyk": "^1.316.1" }, "scripts": { "snyk-protect": "snyk protect", "prepublish": "npm run snyk-protect" }, "snyk": true } ================================================ FILE: extensions/exchanges/gemini/products.json ================================================ [ { "asset": "BTC", "currency": "USD", "min_size": "0.00001", "max_size": "10000", "increment": "0.01", "label": "BTC/USD" }, { "asset": "BTC", "currency": "DAI", "min_size": "0.00001", "max_size": "10000", "increment": "0.01", "label": "BTC/DAI" }, { "asset": "BTC", "currency": "GBP", "min_size": "0.00001", "max_size": "10000", "increment": "0.01", "label": "BTC/GBP" }, { "asset": "BTC", "currency": "EUR", "min_size": "0.00001", "max_size": "10000", "increment": "0.01", "label": "BTC/EUR" }, { "asset": "BTC", "currency": "SGD", "min_size": "0.00001", "max_size": "10000", "increment": "0.01", "label": "BTC/SGD" }, { "asset": "ETH", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "ETH/BTC" }, { "asset": "ETH", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ETH/USD" }, { "asset": "ETH", "currency": "GBP", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ETH/GBP" }, { "asset": "ETH", "currency": "EUR", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ETH/EUR" }, { "asset": "ETH", "currency": "SGD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ETH/SGD" }, { "asset": "ETH", "currency": "DAI", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ETH/DAI" }, { "asset": "BCH", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BCH/USD" }, { "asset": "BCH", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "BCH/BTC" }, { "asset": "BCH", "currency": "ETH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BCH/ETH" }, { "asset": "LTC", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LTC/USD" }, { "asset": "LTC", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "LTC/BTC" }, { "asset": "LTC", "currency": "ETH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LTC/ETH" }, { "asset": "LTC", "currency": "BCH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LTC/BCH" }, { "asset": "ZEC", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ZEC/USD" }, { "asset": "ZEC", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "ZEC/BTC" }, { "asset": "ZEC", "currency": "ETH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ZEC/ETH" }, { "asset": "ZEC", "currency": "BCH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ZEC/BCH" }, { "asset": "ZEC", "currency": "LTC", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ZEC/LTC" }, { "asset": "BAT", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BAT/USD" }, { "asset": "BAT", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "BAT/BTC" }, { "asset": "BAT", "currency": "ETH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BAT/ETH" }, { "asset": "LIN", "currency": "KUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LIN/KUS" }, { "asset": "LIN", "currency": "KBT", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LIN/KBT" }, { "asset": "LIN", "currency": "KET", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LIN/KET" }, { "asset": "DAI", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "DAI/USD" }, { "asset": "OXT", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "OXT/USD" }, { "asset": "OXT", "currency": "BTC", "min_size": "0.001", "max_size": "10000", "increment": "0.00001", "label": "OXT/BTC" }, { "asset": "OXT", "currency": "ETH", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "OXT/ETH" }, { "asset": "FIL", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "FIL/USD" }, { "asset": "AMP", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "AMP/USD" }, { "asset": "PAX", "currency": "GUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "PAX/GUS" }, { "asset": "COM", "currency": "PUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "COM/PUS" }, { "asset": "MKR", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "MKR/USD" }, { "asset": "ZRX", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ZRX/USD" }, { "asset": "KNC", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "KNC/USD" }, { "asset": "STO", "currency": "RJU", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "STO/RJU" }, { "asset": "MAN", "currency": "AUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "MAN/AUS" }, { "asset": "AAV", "currency": "EUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "AAV/EUS" }, { "asset": "SNX", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "SNX/USD" }, { "asset": "YFI", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "YFI/USD" }, { "asset": "UMA", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "UMA/USD" }, { "asset": "BAL", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BAL/USD" }, { "asset": "CRV", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "CRV/USD" }, { "asset": "REN", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "REN/USD" }, { "asset": "UNI", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "UNI/USD" }, { "asset": "ENJ", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "ENJ/USD" }, { "asset": "BNT", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BNT/USD" }, { "asset": "1IN", "currency": "CHU", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "1IN/CHU" }, { "asset": "SKL", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "SKL/USD" }, { "asset": "GRT", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "GRT/USD" }, { "asset": "LRC", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LRC/USD" }, { "asset": "SAN", "currency": "DUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "SAN/DUS" }, { "asset": "CUB", "currency": "EUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "CUB/EUS" }, { "asset": "LPT", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "LPT/USD" }, { "asset": "BON", "currency": "DUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "BON/DUS" }, { "asset": "MAT", "currency": "ICU", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "MAT/ICU" }, { "asset": "INJ", "currency": "USD", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "INJ/USD" }, { "asset": "SUS", "currency": "HIU", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "SUS/HIU" }, { "asset": "DOG", "currency": "EUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "DOG/EUS" }, { "asset": "GUS", "currency": "DUS", "min_size": "0.001", "max_size": "10000", "increment": "0.01", "label": "GUS/DUS" } ] ================================================ FILE: extensions/exchanges/gemini/update-products.sh ================================================ #!/usr/bin/env node var request = require('micro-request') request('https://api.gemini.com/v1/symbols', {headers: {'User-Agent': 'zenbot/4'}}, function (err, resp, body) { if (err) throw err if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body console.error(err) process.exit(1) } var products = [] body.forEach(function (product) { products.push({ asset: product.substring(0, 3).toUpperCase(), currency: product.substring(3, 6).toUpperCase(), min_size: (product.substring(0, 3).toUpperCase() === 'BTC') ? '0.00001' : '0.001', max_size: '10000', increment: (product.substring(3, 6).toUpperCase() === 'BTC') ? '0.00001' : '0.01', label: product.substring(0, 3).toUpperCase() + '/' + product.substring(3, 6).toUpperCase() }) }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) ================================================ FILE: extensions/exchanges/hitbtc/exchange.js ================================================ const ccxt = require('ccxt') const path = require('path') module.exports = function container (conf) { //let recoverableErrors = new RegExp(/(ESOCKETTIMEOUT|ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|Invalid nonce|Rate limit exceeded|URL request error)/) var public_client, authed_client function publicClient () { if (!public_client) public_client = new ccxt.hitbtc({ 'apiKey': '', 'secret': '' }) return public_client } function authedClient() { if (!authed_client) { if (!conf.hitbtc || !conf.hitbtc.key || !conf.hitbtc.key === 'YOUR-API-KEY') { throw new Error('please configure your HitBTC credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new ccxt.hitbtc({ 'apiKey': conf.hitbtc.key, 'secret': conf.hitbtc.secret }) } return authed_client } function joinProduct(product_id) { return product_id.split('-')[0] + '/' + product_id.split('-')[1] } function retry (method, args, err) { var timeout = 5000 if (method == 'getOrder') { // it can take up to 30 seconds for hitbtc to update with an order change. if (err) if (err.message.match(/not found/)) { timeout = 7000 } } if (err) if (err.message) if (err.message.match(/Rate limit exceeded/)) { timeout = 10000 } setTimeout(function () { exchange[method].apply(exchange, args) }, timeout) return false } // function handleErrors(command, err, data, args, callback) { // if (err) // { // if (err.message && err.message.match(recoverableErrors)) { // return retry(command, args, err) // } // return callback(err, []) // } // if (typeof data !== 'object') { // console.log(`bittrex API ${command} had an abnormal response, quitting.`) // return callback(null, []) // } // // generic error handler data was null and err was null // if (data == null) // { // return retry(command, args, err) // } // // specific handlers // if ((command == 'getQuote' || command == 'getTrades') && data.result == null ) // { // return retry(command, args, data) // } // if(!data.success) { // if (data.message && data.message.match(recoverableErrors)) { // return retry(command, args, data.message) // } // return callback(null, []) // } // return true // } var firstRun = true var exchange = { name: 'hitbtc', historyScan: 'forward', makerFee: -0.01, takerFee: 0.1, getProducts: function () { if (firstRun) { firstRun = false var client = publicClient() this.makerFee = client.fees.trading.maker * 100 this.takerFee = client.fees.trading.taker * 100 } return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() { client.fetchTrades(joinProduct(opts.product_id),opts.from) .then(result => { var trades = result.map(function (trade) { return { trade_id: trade.id, time: trade.timestamp, size: parseFloat(trade.amount), price: parseFloat(trade.price), selector: 'hitbtc.'+opts.product_id, side: trade.side } }) cb(null, trades) }) .catch(function (error) { return retry('getTrades', func_args,error) }) } }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.fetchBalance() .then(result => { var balance = {asset: 0, currency: 0} Object.keys(result).forEach(function (key) { if (key === opts.currency) { balance.currency = result[key].free balance.currency_hold = result[key].used } if (key === opts.asset) { balance.asset = result[key].free balance.asset_hold = result[key].used } }) cb(null, balance) }) .catch(function (error) { return retry('getBalance', func_args,error) }) }, getQuote: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchTicker(joinProduct(opts.product_id)) .then(result => { cb(null, { bid: result.bid, ask: result.ask }) }) .catch(function (error) { return retry('getQuote', func_args,error) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.cancelOrder(opts.order_id,joinProduct(opts.product_id) ) .then( (result) => { cb(result) }) .catch(function (error) { return retry('cancelOrder', func_args,error) }) }, buy: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { opts.type = 'market' } if (opts.order_type == 'maker') { opts.type = 'limit' } opts.side = 'buy' let callParams = { symbol : joinProduct(opts.product_id), type : opts.type, side: 'buy', quantity: opts.size, price: opts.price } client.createOrder( callParams.symbol, callParams.type, callParams.side, callParams.quantity, callParams.price) .then(result => { cb(null, result) }).catch(function (error) { if (error.message.match(/Insufficient funds/)) { let order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } return retry('buy', func_args) }) }, sell: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { opts.type = 'market' } if (opts.order_type == 'maker') { opts.type = 'limit' } opts.side = 'sell' let callParams = { symbol : joinProduct(opts.product_id), type : opts.type, side: 'sell', quantity: opts.size, price: opts.price } client.createOrder(callParams.symbol, callParams.type, callParams.side, callParams.quantity, callParams.price) .then(result => { let order = { id: result ? result.id : null, status: 'open', price: opts.price, size: opts.size, post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0', ordertype: opts.order_type } return cb(null, order) }).catch(function (error) { if (error.message.match(/Insufficient funds/)) { let order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } return retry('sell', func_args, error) }) }, getOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.fetchOrder(opts.order_id, joinProduct(opts.product_id),{wait:100000}) .then( result => { let r = result if (result.status === 'canceled') { // order was cancelled. recall from cache return cb({message:'Order not found',desc:'Order cancel or deleted'}) } if (result.status == 'open') { result.status = 'open' result.filled_size = parseFloat(result.amount) - parseFloat(result.remaining) return cb(null, result) } if (result.status == 'done' || result.status == 'closed') { result.status = 'done' result.done_at = new Date().getTime() result.filled_size = parseFloat(result.amount) - parseFloat(result.remaining) return cb(null, result) } return cb(null,r) }).catch(function (error) { return retry('getOrder', func_args,error) }) }, getCursor: function (trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/hitbtc/products.json ================================================ [ { "asset": "BCN", "currency": "BTC", "min_size": 100, "increment": "0.0000000001", "label": "BCN/BTC" }, { "asset": "BTC", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "BTC/USDT" }, { "asset": "DASH", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DASH/BTC" }, { "asset": "DOGE", "currency": "BTC", "min_size": 1000, "increment": "0.000000001", "label": "DOGE/BTC" }, { "asset": "DOGE", "currency": "USDT", "min_size": 10, "increment": "0.000001000000000000", "label": "DOGE/USDT" }, { "asset": "DSH", "currency": "BTC", "min_size": 1, "increment": "0.000000001", "label": "DSH/BTC" }, { "asset": "EMC", "currency": "BTC", "min_size": 0.1, "increment": "0.00000001", "label": "EMC/BTC" }, { "asset": "ETH", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ETH/BTC" }, { "asset": "FCN", "currency": "BTC", "min_size": 0.01, "increment": "0.000001000000000000", "label": "FCN/BTC" }, { "asset": "LSK", "currency": "BTC", "min_size": 0.01, "increment": "0.0000001", "label": "LSK/BTC" }, { "asset": "LTC", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "LTC/BTC" }, { "asset": "LTC", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "LTC/USDT" }, { "asset": "NXT", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "NXT/BTC" }, { "asset": "QCN", "currency": "BTC", "min_size": 0.01, "increment": "0.000001000000000000", "label": "QCN/BTC" }, { "asset": "SBD", "currency": "BTC", "min_size": 0.001, "increment": "0.000010000000000000", "label": "SBD/BTC" }, { "asset": "SC", "currency": "BTC", "min_size": 100, "increment": "0.000000001", "label": "SC/BTC" }, { "asset": "STEEM", "currency": "BTC", "min_size": 0.001, "increment": "0.000010000000000000", "label": "STEEM/BTC" }, { "asset": "XDN", "currency": "BTC", "min_size": 100, "increment": "0.0000000001", "label": "XDN/BTC" }, { "asset": "XEM", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "XEM/BTC" }, { "asset": "XMR", "currency": "BTC", "min_size": 0.01, "increment": "0.000001000000000000", "label": "XMR/BTC" }, { "asset": "ARDR", "currency": "BTC", "min_size": 1, "increment": "0.000000001", "label": "ARDR/BTC" }, { "asset": "ZEC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ZEC/BTC" }, { "asset": "WAVES", "currency": "BTC", "min_size": 0.01, "increment": "0.0000001", "label": "WAVES/BTC" }, { "asset": "MAID", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "MAID/BTC" }, { "asset": "AMP", "currency": "BTC", "min_size": 0.1, "increment": "0.00000001", "label": "AMP/BTC" }, { "asset": "BUS", "currency": "BTC", "min_size": 0.0001, "increment": "0.000010000000000000", "label": "BUS/BTC" }, { "asset": "DGD", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DGD/BTC" }, { "asset": "ICN", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ICN/BTC" }, { "asset": "SNGLS", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "SNGLS/BTC" }, { "asset": "1ST", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "1ST/BTC" }, { "asset": "TRST", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "TRST/BTC" }, { "asset": "TIME", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "TIME/BTC" }, { "asset": "GNO", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "GNO/BTC" }, { "asset": "REP", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "REP/BTC" }, { "asset": "XMR", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "XMR/USDT" }, { "asset": "DASH", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "DASH/USDT" }, { "asset": "ETH", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "ETH/USDT" }, { "asset": "NXT", "currency": "USDT", "min_size": 1, "increment": "0.000010000000000000", "label": "NXT/USDT" }, { "asset": "ZRC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ZRC/BTC" }, { "asset": "BOS", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BOS/BTC" }, { "asset": "DCT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DCT/BTC" }, { "asset": "ANT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ANT/BTC" }, { "asset": "AEON", "currency": "BTC", "min_size": 0.1, "increment": "0.00000001", "label": "AEON/BTC" }, { "asset": "GUP", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "GUP/BTC" }, { "asset": "PLU", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "PLU/BTC" }, { "asset": "LUN", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "LUN/BTC" }, { "asset": "TAAS", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "TAAS/BTC" }, { "asset": "NXC", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "NXC/BTC" }, { "asset": "EDG", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "EDG/BTC" }, { "asset": "RLC", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "RLC/BTC" }, { "asset": "SWT", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "SWT/BTC" }, { "asset": "TKN", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "TKN/BTC" }, { "asset": "WINGS", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "WINGS/BTC" }, { "asset": "XAUR", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "XAUR/BTC" }, { "asset": "AE", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "AE/BTC" }, { "asset": "PTOY", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "PTOY/BTC" }, { "asset": "ZEC", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "ZEC/USDT" }, { "asset": "XEM", "currency": "USDT", "min_size": 1, "increment": "0.000001000000000000", "label": "XEM/USDT" }, { "asset": "BCN", "currency": "USDT", "min_size": 10, "increment": "0.000001000000000000", "label": "BCN/USDT" }, { "asset": "XDN", "currency": "USDT", "min_size": 10, "increment": "0.000001000000000000", "label": "XDN/USDT" }, { "asset": "MAID", "currency": "USDT", "min_size": 1, "increment": "0.000001000000000000", "label": "MAID/USDT" }, { "asset": "ETC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ETC/BTC" }, { "asset": "ETC", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "ETC/USDT" }, { "asset": "CFI", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "CFI/BTC" }, { "asset": "PLBT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "PLBT/BTC" }, { "asset": "BNT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BNT/BTC" }, { "asset": "XDNCO", "currency": "BTC", "min_size": 100000, "increment": "0.0000000001", "label": "XDNCO/BTC" }, { "asset": "FYN", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "FYN/ETH" }, { "asset": "SNM", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SNM/ETH" }, { "asset": "SNT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SNT/ETH" }, { "asset": "CVC", "currency": "USDT", "min_size": 0.01, "increment": "0.000100000000000000", "label": "CVC/USDT" }, { "asset": "PAY", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PAY/ETH" }, { "asset": "OAX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "OAX/ETH" }, { "asset": "OMG", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "OMG/ETH" }, { "asset": "BQX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BQX/ETH" }, { "asset": "XTZ", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "XTZ/BTC" }, { "asset": "DICE", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DICE/BTC" }, { "asset": "CFI", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "CFI/ETH" }, { "asset": "PTOY", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PTOY/ETH" }, { "asset": "1ST", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "1ST/ETH" }, { "asset": "XAUR", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "XAUR/ETH" }, { "asset": "TAAS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "TAAS/ETH" }, { "asset": "TIME", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "TIME/ETH" }, { "asset": "DICE", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "DICE/ETH" }, { "asset": "SWT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SWT/ETH" }, { "asset": "XMR", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "XMR/ETH" }, { "asset": "ETC", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ETC/ETH" }, { "asset": "DASH", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "DASH/ETH" }, { "asset": "ZEC", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ZEC/ETH" }, { "asset": "PLU", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PLU/ETH" }, { "asset": "GNO", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "GNO/ETH" }, { "asset": "XRP", "currency": "BTC", "min_size": 1, "increment": "0.00000001", "label": "XRP/BTC" }, { "asset": "NET", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "NET/ETH" }, { "asset": "STRAT", "currency": "USDT", "min_size": 0.001, "increment": "0.010000000000000000", "label": "STRAT/USDT" }, { "asset": "STRAT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "STRAT/BTC" }, { "asset": "SNC", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SNC/ETH" }, { "asset": "ADX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ADX/ETH" }, { "asset": "BET", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BET/ETH" }, { "asset": "EOS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "EOS/ETH" }, { "asset": "DENT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "DENT/ETH" }, { "asset": "SAN", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SAN/ETH" }, { "asset": "EOS", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "EOS/BTC" }, { "asset": "EOS", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "EOS/USDT" }, { "asset": "MNE", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "MNE/BTC" }, { "asset": "MSP", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "MSP/ETH" }, { "asset": "DDF", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "DDF/ETH" }, { "asset": "XTZ", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "XTZ/ETH" }, { "asset": "XTZ", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "XTZ/USDT" }, { "asset": "UET", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "UET/ETH" }, { "asset": "MYB", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "MYB/ETH" }, { "asset": "SUR", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "SUR/ETH" }, { "asset": "IXT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "IXT/ETH" }, { "asset": "PLR", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PLR/ETH" }, { "asset": "TIX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "TIX/ETH" }, { "asset": "NDC", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "NDC/ETH" }, { "asset": "PRO", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PRO/ETH" }, { "asset": "AVT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "AVT/ETH" }, { "asset": "COSS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "COSS/ETH" }, { "asset": "EVX", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "EVX/USDT" }, { "asset": "DLT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DLT/BTC" }, { "asset": "BNT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BNT/ETH" }, { "asset": "BNT", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "BNT/USDT" }, { "asset": "QAU", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "QAU/BTC" }, { "asset": "QAU", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "QAU/ETH" }, { "asset": "MANA", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "MANA/USDT" }, { "asset": "DNT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "DNT/BTC" }, { "asset": "FYP", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "FYP/BTC" }, { "asset": "OPT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "OPT/BTC" }, { "asset": "TNT", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "TNT/ETH" }, { "asset": "STX", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "STX/BTC" }, { "asset": "STX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "STX/ETH" }, { "asset": "STX", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "STX/USDT" }, { "asset": "TNT", "currency": "USDT", "min_size": 0.01, "increment": "0.000100000000000000", "label": "TNT/USDT" }, { "asset": "TNT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "TNT/BTC" }, { "asset": "BitClave", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BitClave/BTC" }, { "asset": "BitClave", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BitClave/ETH" }, { "asset": "BitClave", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "BitClave/USDT" }, { "asset": "BCH", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BCH/BTC" }, { "asset": "BCH", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BCH/ETH" }, { "asset": "BCH", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "BCH/USDT" }, { "asset": "ENG", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ENG/ETH" }, { "asset": "XUC", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "XUC/USDT" }, { "asset": "SNC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "SNC/BTC" }, { "asset": "SNC", "currency": "USDT", "min_size": 0.01, "increment": "0.000100000000000000", "label": "SNC/USDT" }, { "asset": "OAX", "currency": "USDT", "min_size": 0.01, "increment": "0.000100000000000000", "label": "OAX/USDT" }, { "asset": "OAX", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "OAX/BTC" }, { "asset": "BAS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BAS/ETH" }, { "asset": "ZRX", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ZRX/BTC" }, { "asset": "ZRX", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ZRX/ETH" }, { "asset": "ZRX", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "ZRX/USDT" }, { "asset": "RVT", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "RVT/BTC" }, { "asset": "ICOS", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "ICOS/BTC" }, { "asset": "ICOS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "ICOS/ETH" }, { "asset": "ICOS", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "ICOS/USDT" }, { "asset": "PPC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "PPC/BTC" }, { "asset": "PPC", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "PPC/USDT" }, { "asset": "QTUM", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "QTUM/ETH" }, { "asset": "VERI", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "VERI/BTC" }, { "asset": "VERI", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "VERI/ETH" }, { "asset": "VERI", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "VERI/USDT" }, { "asset": "IGNIS", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "IGNIS/ETH" }, { "asset": "PRG", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "PRG/BTC" }, { "asset": "PRG", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "PRG/ETH" }, { "asset": "PRG", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "PRG/USDT" }, { "asset": "BMC", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BMC/BTC" }, { "asset": "BMC", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BMC/ETH" }, { "asset": "BMC", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "BMC/USDT" }, { "asset": "CND", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "CND/BTC" }, { "asset": "CND", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "CND/ETH" }, { "asset": "CND", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "CND/USDT" }, { "asset": "SKIN", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "SKIN/BTC" }, { "asset": "MGO", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "MGO/BTC" }, { "asset": "MGO", "currency": "USDT", "min_size": 0.01, "increment": "0.000010000000000000", "label": "MGO/USDT" }, { "asset": "CDT", "currency": "ETH", "min_size": 1, "increment": "0.0000001", "label": "CDT/ETH" }, { "asset": "CDT", "currency": "USDT", "min_size": 0.1, "increment": "0.000001000000000000", "label": "CDT/USDT" }, { "asset": "FUN", "currency": "BTC", "min_size": 10, "increment": "0.00000001", "label": "FUN/BTC" }, { "asset": "FUN", "currency": "ETH", "min_size": 10, "increment": "0.0000001", "label": "FUN/ETH" }, { "asset": "FUN", "currency": "USDT", "min_size": 1, "increment": "0.0000001", "label": "FUN/USDT" }, { "asset": "HVN", "currency": "BTC", "min_size": 10, "increment": "0.00000001", "label": "HVN/BTC" }, { "asset": "HVN", "currency": "ETH", "min_size": 10, "increment": "0.0000001", "label": "HVN/ETH" }, { "asset": "FUEL", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "FUEL/BTC" }, { "asset": "FUEL", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "FUEL/ETH" }, { "asset": "FUEL", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "FUEL/USDT" }, { "asset": "POE", "currency": "BTC", "min_size": 10, "increment": "0.000000001", "label": "POE/BTC" }, { "asset": "POE", "currency": "ETH", "min_size": 10, "increment": "0.00000001", "label": "POE/ETH" }, { "asset": "MCAP", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "MCAP/BTC" }, { "asset": "AIR", "currency": "BTC", "min_size": 10, "increment": "0.00000001", "label": "AIR/BTC" }, { "asset": "AIR", "currency": "ETH", "min_size": 10, "increment": "0.0000001", "label": "AIR/ETH" }, { "asset": "AIR", "currency": "USDT", "min_size": 10, "increment": "0.0000001", "label": "AIR/USDT" }, { "asset": "AMB", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "AMB/USDT" }, { "asset": "AMB", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "AMB/ETH" }, { "asset": "AMB", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "AMB/BTC" }, { "asset": "NTO", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "NTO/BTC" }, { "asset": "ICO", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ICO/BTC" }, { "asset": "PING", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "PING/BTC" }, { "asset": "RKC", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "RKC/ETH" }, { "asset": "GAME", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "GAME/BTC" }, { "asset": "TKR", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "TKR/ETH" }, { "asset": "HPC", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "HPC/BTC" }, { "asset": "PPT", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "PPT/ETH" }, { "asset": "MTH", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "MTH/BTC" }, { "asset": "MTH", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "MTH/ETH" }, { "asset": "WMGO", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "WMGO/BTC" }, { "asset": "WMGO", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "WMGO/USDT" }, { "asset": "LRC", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "LRC/BTC" }, { "asset": "LRC", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "LRC/ETH" }, { "asset": "ICX", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ICX/BTC" }, { "asset": "ICX", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "ICX/ETH" }, { "asset": "NEO", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "NEO/BTC" }, { "asset": "NEO", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "NEO/ETH" }, { "asset": "NEO", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "NEO/USDT" }, { "asset": "CSNO", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "CSNO/BTC" }, { "asset": "ORME", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "ORME/BTC" }, { "asset": "ICX", "currency": "USDT", "min_size": 100, "increment": "0.000100000000000000", "label": "ICX/USDT" }, { "asset": "PIX", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "PIX/BTC" }, { "asset": "PIX", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "PIX/ETH" }, { "asset": "IND", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "IND/ETH" }, { "asset": "KICK", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "KICK/BTC" }, { "asset": "YOYOW", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "YOYOW/BTC" }, { "asset": "MIPS", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "MIPS/BTC" }, { "asset": "CDT", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "CDT/BTC" }, { "asset": "XVG", "currency": "BTC", "min_size": 1000, "increment": "0.00000001", "label": "XVG/BTC" }, { "asset": "XVG", "currency": "ETH", "min_size": 1000, "increment": "0.0000001", "label": "XVG/ETH" }, { "asset": "XVG", "currency": "USDT", "min_size": 1000, "increment": "0.000001000000000000", "label": "XVG/USDT" }, { "asset": "DGB", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "DGB/BTC" }, { "asset": "DGB", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "DGB/ETH" }, { "asset": "DGB", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "DGB/USDT" }, { "asset": "DCN", "currency": "ETH", "min_size": 10000, "increment": "0.00000001", "label": "DCN/ETH" }, { "asset": "DCN", "currency": "USDT", "min_size": 1000, "increment": "0.000001000000000000", "label": "DCN/USDT" }, { "asset": "LAT", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "LAT/BTC" }, { "asset": "CCT", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "CCT/ETH" }, { "asset": "EBET", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "EBET/ETH" }, { "asset": "VIBE", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "VIBE/BTC" }, { "asset": "VOISE", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "VOISE/BTC" }, { "asset": "ENJ", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ENJ/BTC" }, { "asset": "ENJ", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "ENJ/ETH" }, { "asset": "ENJ", "currency": "USDT", "min_size": 100, "increment": "0.000010000000000000", "label": "ENJ/USDT" }, { "asset": "ZSC", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ZSC/BTC" }, { "asset": "ZSC", "currency": "ETH", "min_size": 100, "increment": "0.000010000000000000", "label": "ZSC/ETH" }, { "asset": "ZSC", "currency": "USDT", "min_size": 100, "increment": "0.000010000000000000", "label": "ZSC/USDT" }, { "asset": "ETBS", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "ETBS/BTC" }, { "asset": "TRX", "currency": "BTC", "min_size": 1000, "increment": "0.00000001", "label": "TRX/BTC" }, { "asset": "TRX", "currency": "ETH", "min_size": 1000, "increment": "0.0000001", "label": "TRX/ETH" }, { "asset": "TRX", "currency": "USDT", "min_size": 100, "increment": "0.000010000000000000", "label": "TRX/USDT" }, { "asset": "VEN", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "VEN/BTC" }, { "asset": "VEN", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "VEN/ETH" }, { "asset": "VEN", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "VEN/USDT" }, { "asset": "ART", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ART/BTC" }, { "asset": "EVX", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "EVX/BTC" }, { "asset": "EVX", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "EVX/ETH" }, { "asset": "QVT", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "QVT/ETH" }, { "asset": "EBTCOLD", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "EBTCOLD/BTC" }, { "asset": "EBTCOLD", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "EBTCOLD/ETH" }, { "asset": "EBTCOLD", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "EBTCOLD/USDT" }, { "asset": "BKB", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "BKB/BTC" }, { "asset": "EXN", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "EXN/BTC" }, { "asset": "TGT", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "TGT/BTC" }, { "asset": "ATS", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "ATS/ETH" }, { "asset": "UGT", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "UGT/BTC" }, { "asset": "UGT", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "UGT/ETH" }, { "asset": "UGT", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "UGT/USDT" }, { "asset": "CTR", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "CTR/BTC" }, { "asset": "CTR", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "CTR/ETH" }, { "asset": "CTR", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "CTR/USDT" }, { "asset": "BMT", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "BMT/BTC" }, { "asset": "BMT", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "BMT/ETH" }, { "asset": "SUB", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "SUB/BTC" }, { "asset": "SUB", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "SUB/ETH" }, { "asset": "SUB", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "SUB/USDT" }, { "asset": "WTC", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "WTC/BTC" }, { "asset": "CNX", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "CNX/BTC" }, { "asset": "ATB", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "ATB/BTC" }, { "asset": "ATB", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "ATB/ETH" }, { "asset": "ATB", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "ATB/USDT" }, { "asset": "ODN", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ODN/BTC" }, { "asset": "BTM", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "BTM/BTC" }, { "asset": "BTM", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "BTM/ETH" }, { "asset": "BTM", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "BTM/USDT" }, { "asset": "B2X", "currency": "BTC", "min_size": 0.001, "increment": "0.000010000000000000", "label": "B2X/BTC" }, { "asset": "B2X", "currency": "ETH", "min_size": 0.01, "increment": "0.000010000000000000", "label": "B2X/ETH" }, { "asset": "B2X", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "B2X/USDT" }, { "asset": "ATM", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ATM/BTC" }, { "asset": "ATM", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "ATM/ETH" }, { "asset": "ATM", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "ATM/USDT" }, { "asset": "LIFE", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "LIFE/BTC" }, { "asset": "VIB", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "VIB/BTC" }, { "asset": "VIB", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "VIB/ETH" }, { "asset": "VIB", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "VIB/USDT" }, { "asset": "DRT", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "DRT/ETH" }, { "asset": "STU", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "STU/USDT" }, { "asset": "HDG", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "HDG/ETH" }, { "asset": "OMG", "currency": "BTC", "min_size": 0.01, "increment": "0.000100000000000000", "label": "OMG/BTC" }, { "asset": "PAY", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "PAY/BTC" }, { "asset": "COSS", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "COSS/BTC" }, { "asset": "PPT", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "PPT/BTC" }, { "asset": "SNT", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "SNT/BTC" }, { "asset": "BTG", "currency": "BTC", "min_size": 0.001, "increment": "0.000001000000000000", "label": "BTG/BTC" }, { "asset": "BTG", "currency": "ETH", "min_size": 0.01, "increment": "0.000001000000000000", "label": "BTG/ETH" }, { "asset": "BTG", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "BTG/USDT" }, { "asset": "SMART", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "SMART/BTC" }, { "asset": "SMART", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "SMART/ETH" }, { "asset": "SMART", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "SMART/USDT" }, { "asset": "XUC", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "XUC/ETH" }, { "asset": "XUC", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "XUC/BTC" }, { "asset": "CL", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "CL/BTC" }, { "asset": "CL", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "CL/ETH" }, { "asset": "CL", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "CL/USDT" }, { "asset": "LA", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "LA/ETH" }, { "asset": "CLD", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "CLD/BTC" }, { "asset": "CLD", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "CLD/ETH" }, { "asset": "CLD", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "CLD/USDT" }, { "asset": "ELM", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ELM/BTC" }, { "asset": "EDO", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "EDO/BTC" }, { "asset": "EDO", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "EDO/ETH" }, { "asset": "EDO", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "EDO/USDT" }, { "asset": "HGT", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "HGT/ETH" }, { "asset": "POLL", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "POLL/BTC" }, { "asset": "IXT", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "IXT/BTC" }, { "asset": "ATS", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "ATS/BTC" }, { "asset": "SCL", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "SCL/BTC" }, { "asset": "ATL", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ATL/BTC" }, { "asset": "EBTC", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "EBTC/BTC" }, { "asset": "EBTC", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "EBTC/ETH" }, { "asset": "EBTC", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "EBTC/USDT" }, { "asset": "ETP", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "ETP/BTC" }, { "asset": "ETP", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "ETP/ETH" }, { "asset": "ETP", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "ETP/USDT" }, { "asset": "OTX", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "OTX/BTC" }, { "asset": "CDX", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "CDX/ETH" }, { "asset": "DRPU", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "DRPU/BTC" }, { "asset": "NEBL", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "NEBL/BTC" }, { "asset": "NEBL", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "NEBL/ETH" }, { "asset": "HAC", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "HAC/BTC" }, { "asset": "CTX", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "CTX/BTC" }, { "asset": "CTX", "currency": "ETH", "min_size": 100, "increment": "0.000001000000000000", "label": "CTX/ETH" }, { "asset": "ELE", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ELE/BTC" }, { "asset": "ARN", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "ARN/BTC" }, { "asset": "ARN", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "ARN/ETH" }, { "asset": "SISA", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "SISA/BTC" }, { "asset": "SISA", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "SISA/ETH" }, { "asset": "STU", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "STU/BTC" }, { "asset": "STU", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "STU/ETH" }, { "asset": "GVT", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "GVT/ETH" }, { "asset": "INDI", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "INDI/BTC" }, { "asset": "BTX", "currency": "BTC", "min_size": 0.01, "increment": "0.000100000000000000", "label": "BTX/BTC" }, { "asset": "BTX", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "BTX/USDT" }, { "asset": "LTC", "currency": "ETH", "min_size": 0.01, "increment": "0.001000000000000000", "label": "LTC/ETH" }, { "asset": "BCN", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "BCN/ETH" }, { "asset": "MAID", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "MAID/ETH" }, { "asset": "NXT", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "NXT/ETH" }, { "asset": "STRAT", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "STRAT/ETH" }, { "asset": "XDN", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "XDN/ETH" }, { "asset": "XEM", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "XEM/ETH" }, { "asset": "PLR", "currency": "BTC", "min_size": 1, "increment": "0.000010000000000000", "label": "PLR/BTC" }, { "asset": "SUR", "currency": "BTC", "min_size": 0.1, "increment": "0.000100000000000000", "label": "SUR/BTC" }, { "asset": "BQX", "currency": "BTC", "min_size": 0.1, "increment": "0.000100000000000000", "label": "BQX/BTC" }, { "asset": "DOGE", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "DOGE/ETH" }, { "asset": "ITS", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ITS/BTC" }, { "asset": "AMM", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "AMM/BTC" }, { "asset": "AMM", "currency": "ETH", "min_size": 10, "increment": "0.000010000000000000", "label": "AMM/ETH" }, { "asset": "AMM", "currency": "USDT", "min_size": 10, "increment": "0.000100000000000000", "label": "AMM/USDT" }, { "asset": "DBIX", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "DBIX/BTC" }, { "asset": "PRE", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "PRE/BTC" }, { "asset": "KBR", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "KBR/BTC" }, { "asset": "TBT", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "TBT/BTC" }, { "asset": "ERO", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ERO/BTC" }, { "asset": "SMS", "currency": "BTC", "min_size": 0.01, "increment": "0.000100000000000000", "label": "SMS/BTC" }, { "asset": "SMS", "currency": "ETH", "min_size": 0.01, "increment": "0.001000000000000000", "label": "SMS/ETH" }, { "asset": "SMS", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "SMS/USDT" }, { "asset": "ZAP", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "ZAP/BTC" }, { "asset": "DOV", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "DOV/BTC" }, { "asset": "DOV", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "DOV/ETH" }, { "asset": "FRD", "currency": "BTC", "min_size": 100, "increment": "0.0000001", "label": "FRD/BTC" }, { "asset": "DRPU", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "DRPU/ETH" }, { "asset": "OTN", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "OTN/BTC" }, { "asset": "XRP", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "XRP/ETH" }, { "asset": "XRP", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "XRP/USDT" }, { "asset": "HSR", "currency": "BTC", "min_size": 10, "increment": "0.000001000000000000", "label": "HSR/BTC" }, { "asset": "LEND", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "LEND/BTC" }, { "asset": "LEND", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "LEND/ETH" }, { "asset": "SPF", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "SPF/ETH" }, { "asset": "SBTC", "currency": "BTC", "min_size": 0.001, "increment": "0.000010000000000000", "label": "SBTC/BTC" }, { "asset": "SBTC", "currency": "ETH", "min_size": 0.01, "increment": "0.000010000000000000", "label": "SBTC/ETH" }, { "asset": "BTCA", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "BTCA/BTC" }, { "asset": "BTCA", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "BTCA/ETH" }, { "asset": "BTCA", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "BTCA/USDT" }, { "asset": "WRC", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "WRC/BTC" }, { "asset": "WRC", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "WRC/ETH" }, { "asset": "WRC", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "WRC/USDT" }, { "asset": "LOC", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "LOC/BTC" }, { "asset": "LOC", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "LOC/ETH" }, { "asset": "LOC", "currency": "USDT", "min_size": 0.001, "increment": "0.100000000000000006", "label": "LOC/USDT" }, { "asset": "SWFTC", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "SWFTC/BTC" }, { "asset": "SWFTC", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "SWFTC/ETH" }, { "asset": "SWFTC", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "SWFTC/USDT" }, { "asset": "STAR", "currency": "ETH", "min_size": 0.001, "increment": "0.010000000000000000", "label": "STAR/ETH" }, { "asset": "SBTC", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "SBTC/USDT" }, { "asset": "STORM", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "STORM/BTC" }, { "asset": "DIM", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "DIM/ETH" }, { "asset": "DIM", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "DIM/USDT" }, { "asset": "DIM", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "DIM/BTC" }, { "asset": "NGC", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "NGC/BTC" }, { "asset": "NGC", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "NGC/ETH" }, { "asset": "NGC", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "NGC/USDT" }, { "asset": "EMC", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "EMC/ETH" }, { "asset": "EMC", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "EMC/USDT" }, { "asset": "MCO", "currency": "BTC", "min_size": 0.001, "increment": "0.001000000000000000", "label": "MCO/BTC" }, { "asset": "MCO", "currency": "ETH", "min_size": 0.001, "increment": "0.010000000000000000", "label": "MCO/ETH" }, { "asset": "MCO", "currency": "USDT", "min_size": 0.001, "increment": "0.100000000000000006", "label": "MCO/USDT" }, { "asset": "MANA", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "MANA/ETH" }, { "asset": "MANA", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "MANA/BTC" }, { "asset": "ECH", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "ECH/BTC" }, { "asset": "CPAY", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "CPAY/ETH" }, { "asset": "DATA", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "DATA/BTC" }, { "asset": "DATA", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "DATA/ETH" }, { "asset": "DATA", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "DATA/USDT" }, { "asset": "UTT", "currency": "BTC", "min_size": 0.1, "increment": "0.000010000000000000", "label": "UTT/BTC" }, { "asset": "UTT", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "UTT/ETH" }, { "asset": "UTT", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "UTT/USDT" }, { "asset": "KMD", "currency": "BTC", "min_size": 0.01, "increment": "0.000100000000000000", "label": "KMD/BTC" }, { "asset": "KMD", "currency": "ETH", "min_size": 0.01, "increment": "0.001000000000000000", "label": "KMD/ETH" }, { "asset": "KMD", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "KMD/USDT" }, { "asset": "QTUM", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "QTUM/USDT" }, { "asset": "QTUM", "currency": "BTC", "min_size": 0.01, "increment": "0.000100000000000000", "label": "QTUM/BTC" }, { "asset": "SNT", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "SNT/USDT" }, { "asset": "OMG", "currency": "USDT", "min_size": 0.01, "increment": "0.010000000000000000", "label": "OMG/USDT" }, { "asset": "EKO", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "EKO/BTC" }, { "asset": "EKO", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "EKO/ETH" }, { "asset": "ADX", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "ADX/BTC" }, { "asset": "ADX", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "ADX/USDT" }, { "asset": "LSK", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "LSK/ETH" }, { "asset": "LSK", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "LSK/USDT" }, { "asset": "PLR", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "PLR/USDT" }, { "asset": "SUR", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "SUR/USDT" }, { "asset": "BQX", "currency": "USDT", "min_size": 1, "increment": "0.000100000000000000", "label": "BQX/USDT" }, { "asset": "DRT", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "DRT/USDT" }, { "asset": "REP", "currency": "ETH", "min_size": 0.1, "increment": "0.000100000000000000", "label": "REP/ETH" }, { "asset": "REP", "currency": "USDT", "min_size": 0.1, "increment": "0.001000000000000000", "label": "REP/USDT" }, { "asset": "TIO", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "TIO/BTC" }, { "asset": "TIO", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "TIO/ETH" }, { "asset": "TIO", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "TIO/USDT" }, { "asset": "WAX", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "WAX/BTC" }, { "asset": "WAX", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "WAX/ETH" }, { "asset": "WAX", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "WAX/USDT" }, { "asset": "ULTC", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "ULTC/BTC" }, { "asset": "EET", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "EET/BTC" }, { "asset": "EET", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "EET/ETH" }, { "asset": "EET", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "EET/USDT" }, { "asset": "C20", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "C20/BTC" }, { "asset": "C20", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "C20/ETH" }, { "asset": "IDH", "currency": "BTC", "min_size": 1, "increment": "0.000001000000000000", "label": "IDH/BTC" }, { "asset": "IDH", "currency": "ETH", "min_size": 1, "increment": "0.000010000000000000", "label": "IDH/ETH" }, { "asset": "IPL", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "IPL/BTC" }, { "asset": "COV", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "COV/BTC" }, { "asset": "COV", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "COV/ETH" }, { "asset": "SENT", "currency": "BTC", "min_size": 10000, "increment": "0.0000000001", "label": "SENT/BTC" }, { "asset": "SENT", "currency": "ETH", "min_size": 10000, "increment": "0.000000001", "label": "SENT/ETH" }, { "asset": "SENT", "currency": "USDT", "min_size": 10000, "increment": "0.00000001", "label": "SENT/USDT" }, { "asset": "SMT", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "SMT/BTC" }, { "asset": "SMT", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "SMT/ETH" }, { "asset": "SMT", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "SMT/USDT" }, { "asset": "W3C", "currency": "BTC", "min_size": 1000, "increment": "0.000000001", "label": "W3C/BTC" }, { "asset": "W3C", "currency": "ETH", "min_size": 1000, "increment": "0.00000001", "label": "W3C/ETH" }, { "asset": "CAS", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "CAS/BTC" }, { "asset": "CAS", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "CAS/ETH" }, { "asset": "CAS", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "CAS/USDT" }, { "asset": "CHAT", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "CHAT/BTC" }, { "asset": "CHAT", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "CHAT/ETH" }, { "asset": "CHAT", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "CHAT/USDT" }, { "asset": "GRMD", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "GRMD/BTC" }, { "asset": "AVH", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "AVH/BTC" }, { "asset": "TRAC", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "TRAC/ETH" }, { "asset": "JNT", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "JNT/ETH" }, { "asset": "CLOUT", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "CLOUT/BTC" }, { "asset": "UTK", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "UTK/BTC" }, { "asset": "UTK", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "UTK/ETH" }, { "asset": "UTK", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "UTK/USDT" }, { "asset": "GNX", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "GNX/ETH" }, { "asset": "CHSB", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "CHSB/BTC" }, { "asset": "CHSB", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "CHSB/ETH" }, { "asset": "AVH", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "AVH/ETH" }, { "asset": "NEU", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "NEU/BTC" }, { "asset": "NEU", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "NEU/ETH" }, { "asset": "NEU", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "NEU/USDT" }, { "asset": "AVH", "currency": "USDT", "min_size": 100, "increment": "0.000001000000000000", "label": "AVH/USDT" }, { "asset": "CLOUT", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "CLOUT/ETH" }, { "asset": "CLOUT", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "CLOUT/USDT" }, { "asset": "TAU", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "TAU/BTC" }, { "asset": "MEK", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "MEK/BTC" }, { "asset": "BAR", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "BAR/BTC" }, { "asset": "BAR", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "BAR/ETH" }, { "asset": "BAR", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "BAR/USDT" }, { "asset": "FLP", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "FLP/BTC" }, { "asset": "FLP", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "FLP/ETH" }, { "asset": "FLP", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "FLP/USDT" }, { "asset": "R", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "R/BTC" }, { "asset": "R", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "R/ETH" }, { "asset": "EKO", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "EKO/USDT" }, { "asset": "PKT", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "PKT/BTC" }, { "asset": "PKT", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "PKT/ETH" }, { "asset": "CPG", "currency": "BTC", "min_size": 100, "increment": "0.00000001", "label": "CPG/BTC" }, { "asset": "CPG", "currency": "ETH", "min_size": 100, "increment": "0.0000001", "label": "CPG/ETH" }, { "asset": "WLK", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "WLK/BTC" }, { "asset": "WLK", "currency": "ETH", "min_size": 10, "increment": "0.000001000000000000", "label": "WLK/ETH" }, { "asset": "WLK", "currency": "USDT", "min_size": 10, "increment": "0.000010000000000000", "label": "WLK/USDT" }, { "asset": "EVN", "currency": "BTC", "min_size": 10, "increment": "0.0000001", "label": "EVN/BTC" } ] ================================================ FILE: extensions/exchanges/hitbtc/update-products.sh ================================================ #!/usr/bin/env node const ccxt = require ('ccxt') const c = require('../../../conf') const n = require('numbro') const hitbtc = new ccxt.hitbtc2 ({ 'apiKey': c.hitbtc.key, 'secret': c.hitbtc.secret, }) hitbtc.fetch_markets() .then(result => { var products = [] result.forEach(function (product) { products.push({ asset: product.base, currency: product.quote, min_size: product.limits.amount.min, max_size: product.limits.amount.max, increment: n(product.step).format('0.000000000000000000'), label: product.symbol }) }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) .catch(function (error) { console.error('An error occurred', error) process.exit(1) }) ================================================ FILE: extensions/exchanges/kraken/exchange.js ================================================ var KrakenClient = require('kraken-api'), minimist = require('minimist'), moment = require('moment'), n = require('numbro'), // eslint-disable-next-line no-unused-vars colors = require('colors') module.exports = function container(conf) { var s = { options: minimist(process.argv) } var so = s.options var public_client, authed_client // var recoverableErrors = new RegExp(/(ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|API:Invalid nonce|API:Rate limit exceeded|between Cloudflare and the origin web server)/) var recoverableErrors = new RegExp(/(ESOCKETTIMEDOUT|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|API:Invalid nonce|between Cloudflare and the origin web server|The web server reported a gateway time-out|The web server reported a bad gateway|525: SSL handshake failed|Service:Unavailable|api.kraken.com \| 522:)/) var silencedRecoverableErrors = new RegExp(/(ESOCKETTIMEDOUT|ETIMEDOUT)/) function publicClient() { if (!public_client) { public_client = new KrakenClient() } return public_client } function authedClient() { if (!authed_client) { if (!conf.kraken || !conf.kraken.key || conf.kraken.key === 'YOUR-API-KEY') { throw new Error('please configure your Kraken credentials in conf.js') } authed_client = new KrakenClient(conf.kraken.key, conf.kraken.secret) } return authed_client } // This is to deal with a silly bug where kraken doesn't use a consistent definition for currency // with certain assets they will mix the use of 'Z' and 'X' prefixes function joinProductFormatted(product_id) { var asset = product_id.split('-')[0] var currency = product_id.split('-')[1] return asset + currency } function retry(method, args, error) { let timeout, errorMsg if (error.message.match(/API:Rate limit exceeded/)) { timeout = 10000 } else { timeout = 150 } // silence common timeout errors if (so.debug || !error.message.match(silencedRecoverableErrors)) { if (error.message.match(/between Cloudflare and the origin web server/)) { errorMsg = 'Connection between Cloudflare CDN and api.kraken.com failed' } else if (error.message.match(/The web server reported a gateway time-out/)) { errorMsg = 'Web server Gateway time-out' } else if (error.message.match(/The web server reported a bad gateway/)) { errorMsg = 'Web server bad Gateway' } else if (error.message.match(/525: SSL handshake failed/)) { errorMsg = 'SSL handshake failed' } else if (error.message.match(/Service:Unavailable/)) { errorMsg = 'Service Unavailable' } else if (error.message.match(/api.kraken.com \| 522:/)) { errorMsg = 'Generic 522 Server error' } else { errorMsg = error } console.warn(('\nKraken API warning - unable to call ' + method + ' (' + errorMsg + '), retrying in ' + timeout / 1000 + 's').yellow) } setTimeout(function() { exchange[method].apply(exchange, args) }, timeout) } var orders = {} var exchange = { name: 'kraken', historyScan: 'forward', makerFee: 0.16, takerFee: 0.26, // The limit for the public API is not documented, 1750 ms between getTrades in backfilling seems to do the trick to omit warning messages. backfillRateLimit: 3500, getProducts: function() { return require('./products.json') }, getTrades: function(opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() var args = { pair: joinProductFormatted(opts.product_id) } if (opts.from) { args.since = Number(opts.from) * 1000000 } client.api('Trades', args, function(error, data) { if (error && error.message.match(recoverableErrors)) { return retry('getTrades', func_args, error) } if (error) { console.error(('\nTrades error:').red) console.error(error) return cb(null, []) } if (data.error.length) { return cb(data.error.join(',')) } var trades = [] Object.keys(data.result[args.pair]).forEach(function(i) { var trade = data.result[args.pair][i] if (!opts.from || (Number(opts.from) < moment.unix((trade[2]).valueOf()))) { trades.push({ trade_id: trade[2] + trade[1] + trade[0], time: moment.unix(trade[2]).valueOf(), size: parseFloat(trade[1]), price: parseFloat(trade[0]), side: trade[3] == 'b' ? 'buy' : 'sell' }) } }) cb(null, trades) }) }, getBalance: function(opts, cb) { var args = [].slice.call(arguments) var client = authedClient() client.api('Balance', null, function(error, data) { var balance = { asset: '0', asset_hold: '0', currency: '0', currency_hold: '0' } if (error) { if (error.message.match(recoverableErrors)) { return retry('getBalance', args, error) } console.error(('\ngetBalance error:').red) console.error(error) return cb(error) } if (data.error.length) { return cb(data.error.join(',')) } if (data.result[opts.currency]) { balance.currency = n(data.result[opts.currency]).format('0.00000000') balance.currency_hold = '0' } if (data.result[opts.asset]) { balance.asset = n(data.result[opts.asset]).format('0.00000000') balance.asset_hold = '0' } cb(null, balance) }) }, getQuote: function(opts, cb) { var args = [].slice.call(arguments) var client = publicClient() var pair = joinProductFormatted(opts.product_id) client.api('Ticker', { pair: pair }, function(error, data) { if (error) { if (error.message.match(recoverableErrors)) { return retry('getQuote', args, error) } console.error(('\ngetQuote error:').red) console.error(error) return cb(error) } if (data.error.length) { return cb(data.error.join(',')) } cb(null, { bid: data.result[pair].b[0], ask: data.result[pair].a[0], }) }) }, cancelOrder: function(opts, cb) { var args = [].slice.call(arguments) var client = authedClient() client.api('CancelOrder', { txid: opts.order_id }, function(error, data) { if (error) { if (error.message.match(recoverableErrors)) { return retry('cancelOrder', args, error) } console.error(('\ncancelOrder error:').red) console.error(error) return cb(error) } if (data.error.length) { return cb(data.error.join(',')) } if (so.debug) { console.log('\nFunction: cancelOrder') console.log(data) } cb(error) }) }, trade: function(type, opts, cb) { var args = [].slice.call(arguments) var client = authedClient() var params = { pair: joinProductFormatted(opts.product_id), type: type, ordertype: (opts.order_type === 'taker' ? 'market' : 'limit'), volume: opts.size, trading_agreement: conf.kraken.tosagree } if (opts.post_only === true && params.ordertype === 'limit') { params.oflags = 'post' } if ('price' in opts) { params.price = opts.price } if (so.debug) { console.log('\nFunction: trade') console.log(params) } client.api('AddOrder', params, function(error, data) { if (error && error.message.match(recoverableErrors)) { return retry('trade', args, error) } var order = { id: data && data.result ? data.result.txid[0] : null, status: 'open', price: opts.price, size: opts.size, created_at: new Date().getTime(), filled_size: '0' } if (opts.order_type === 'maker') { order.post_only = !!opts.post_only } if (so.debug) { console.log('\nData:') console.log(data) console.log('\nOrder:') console.log(order) console.log('\nError:') console.log(error) } if (error) { if (error.message.match(/Order:Insufficient funds$/)) { order.status = 'rejected' order.reject_reason = 'balance' return cb(null, order) } else if (error.message.length) { console.error(('\nUnhandeld AddOrder error:').red) console.error(error) order.status = 'rejected' order.reject_reason = error.message return cb(null, order) } else if (data.error.length) { console.error(('\nUnhandeld AddOrder error:').red) console.error(data.error) order.status = 'rejected' order.reject_reason = data.error.join(',') } } orders['~' + data.result.txid[0]] = order cb(null, order) }) }, buy: function(opts, cb) { exchange.trade('buy', opts, cb) }, sell: function(opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function(opts, cb) { var args = [].slice.call(arguments) var order = orders['~' + opts.order_id] if (!order) return cb(new Error('order not found in cache')) var client = authedClient() var params = { txid: opts.order_id } client.api('QueryOrders', params, function(error, data) { if (error) { if (error.message.match(recoverableErrors)) { return retry('getOrder', args, error) } console.error(('\ngetOrder error:').red) console.error(error) return cb(error) } if (data.error.length) { return cb(data.error.join(',')) } var orderData = data.result[params.txid] if (so.debug) { console.log('\nfunction: QueryOrders') console.log(orderData) } if (!orderData) { return cb('Order not found') } if (orderData.status === 'canceled' && orderData.reason === 'Post only order') { order.status = 'rejected' order.reject_reason = 'post only' order.done_at = new Date().getTime() order.filled_size = '0.00000000' return cb(null, order) } if (orderData.status === 'closed' || (orderData.status === 'canceled' && orderData.reason === 'User canceled')) { order.status = 'done' order.done_at = new Date().getTime() order.filled_size = n(orderData.vol_exec).format('0.00000000') order.price = n(orderData.price).format('0.00000000') return cb(null, order) } cb(null, order) }) }, // return the property used for range querying. getCursor: function(trade) { return (trade.time || trade) } } return exchange } ================================================ FILE: extensions/exchanges/kraken/products.json ================================================ [ { "asset": "AAVE", "currency": "AUD", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "AAVE/AUD" }, { "asset": "AAVE", "currency": "ETH", "min_size": "0.0200000000", "increment": "0.0001000000", "label": "AAVE/ETH" }, { "asset": "AAVE", "currency": "EUR", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "AAVE/EUR" }, { "asset": "AAVE", "currency": "GBP", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "AAVE/GBP" }, { "asset": "AAVE", "currency": "USD", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "AAVE/USD" }, { "asset": "AAVE", "currency": "XBT", "min_size": "0.0200000000", "increment": "0.0000010000", "label": "AAVE/XBT" }, { "asset": "ADA", "currency": "AUD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "ADA/AUD" }, { "asset": "ADA", "currency": "ETH", "min_size": "5.0000000000", "increment": "0.0000001000", "label": "ADA/ETH" }, { "asset": "ADA", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0000010000", "label": "ADA/EUR" }, { "asset": "ADA", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "ADA/GBP" }, { "asset": "ADA", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0000010000", "label": "ADA/USD" }, { "asset": "ADA", "currency": "USDT", "min_size": "5.0000000000", "increment": "0.0000010000", "label": "ADA/USDT" }, { "asset": "ADA", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "ADA/XBT" }, { "asset": "ALGO", "currency": "ETH", "min_size": "5.0000000000", "increment": "0.0000001000", "label": "ALGO/ETH" }, { "asset": "ALGO", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "ALGO/EUR" }, { "asset": "ALGO", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "ALGO/GBP" }, { "asset": "ALGO", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "ALGO/USD" }, { "asset": "ALGO", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "ALGO/XBT" }, { "asset": "ANKR", "currency": "EUR", "min_size": "50.0000000000", "increment": "0.0000100000", "label": "ANKR/EUR" }, { "asset": "ANKR", "currency": "GBP", "min_size": "50.0000000000", "increment": "0.0000100000", "label": "ANKR/GBP" }, { "asset": "ANKR", "currency": "USD", "min_size": "50.0000000000", "increment": "0.0000100000", "label": "ANKR/USD" }, { "asset": "ANKR", "currency": "XBT", "min_size": "50.0000000000", "increment": "0.0000000100", "label": "ANKR/XBT" }, { "asset": "ANT", "currency": "ETH", "min_size": "0.5000000000", "increment": "0.0000010000", "label": "ANT/ETH" }, { "asset": "ANT", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0001000000", "label": "ANT/EUR" }, { "asset": "ANT", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0001000000", "label": "ANT/USD" }, { "asset": "ANT", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000000100", "label": "ANT/XBT" }, { "asset": "ATOM", "currency": "AUD", "min_size": "0.3000000000", "increment": "0.0001000000", "label": "ATOM/AUD" }, { "asset": "ATOM", "currency": "ETH", "min_size": "0.3000000000", "increment": "0.0000010000", "label": "ATOM/ETH" }, { "asset": "ATOM", "currency": "EUR", "min_size": "0.3000000000", "increment": "0.0001000000", "label": "ATOM/EUR" }, { "asset": "ATOM", "currency": "GBP", "min_size": "0.3000000000", "increment": "0.0001000000", "label": "ATOM/GBP" }, { "asset": "ATOM", "currency": "USD", "min_size": "0.3000000000", "increment": "0.0001000000", "label": "ATOM/USD" }, { "asset": "ATOM", "currency": "XBT", "min_size": "0.3000000000", "increment": "0.0000001000", "label": "ATOM/XBT" }, { "asset": "AUD", "currency": "JPY", "min_size": "10.0000000000", "increment": "0.0010000000", "label": "AUD/JPY" }, { "asset": "AUD", "currency": "USD", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "AUD/USD" }, { "asset": "BAL", "currency": "ETH", "min_size": "0.1500000000", "increment": "0.0000100000", "label": "BAL/ETH" }, { "asset": "BAL", "currency": "EUR", "min_size": "0.1500000000", "increment": "0.0100000000", "label": "BAL/EUR" }, { "asset": "BAL", "currency": "USD", "min_size": "0.1500000000", "increment": "0.0100000000", "label": "BAL/USD" }, { "asset": "BAL", "currency": "XBT", "min_size": "0.1500000000", "increment": "0.0000010000", "label": "BAL/XBT" }, { "asset": "BAT", "currency": "ETH", "min_size": "5.0000000000", "increment": "0.0000001000", "label": "BAT/ETH" }, { "asset": "BAT", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "BAT/EUR" }, { "asset": "BAT", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "BAT/USD" }, { "asset": "BAT", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "BAT/XBT" }, { "asset": "BCH", "currency": "AUD", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "BCH/AUD" }, { "asset": "BCH", "currency": "ETH", "min_size": "0.0100000000", "increment": "0.0001000000", "label": "BCH/ETH" }, { "asset": "BCH", "currency": "EUR", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "BCH/EUR" }, { "asset": "BCH", "currency": "GBP", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "BCH/GBP" }, { "asset": "BCH", "currency": "JPY", "min_size": "0.0100000000", "increment": "1.0000000000", "label": "BCH/JPY" }, { "asset": "BCH", "currency": "USD", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "BCH/USD" }, { "asset": "BCH", "currency": "USDT", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "BCH/USDT" }, { "asset": "BCH", "currency": "XBT", "min_size": "0.0100000000", "increment": "0.0000100000", "label": "BCH/XBT" }, { "asset": "BNT", "currency": "EUR", "min_size": "1.0000000000", "increment": "0.0010000000", "label": "BNT/EUR" }, { "asset": "BNT", "currency": "GBP", "min_size": "1.0000000000", "increment": "0.0010000000", "label": "BNT/GBP" }, { "asset": "BNT", "currency": "USD", "min_size": "1.0000000000", "increment": "0.0010000000", "label": "BNT/USD" }, { "asset": "BNT", "currency": "XBT", "min_size": "1.0000000000", "increment": "0.0000001000", "label": "BNT/XBT" }, { "asset": "COMP", "currency": "ETH", "min_size": "0.0100000000", "increment": "0.0001000000", "label": "COMP/ETH" }, { "asset": "COMP", "currency": "EUR", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "COMP/EUR" }, { "asset": "COMP", "currency": "USD", "min_size": "0.0100000000", "increment": "0.0100000000", "label": "COMP/USD" }, { "asset": "COMP", "currency": "XBT", "min_size": "0.0100000000", "increment": "0.0000010000", "label": "COMP/XBT" }, { "asset": "CRV", "currency": "ETH", "min_size": "2.5000000000", "increment": "0.0000010000", "label": "CRV/ETH" }, { "asset": "CRV", "currency": "EUR", "min_size": "2.5000000000", "increment": "0.0010000000", "label": "CRV/EUR" }, { "asset": "CRV", "currency": "USD", "min_size": "2.5000000000", "increment": "0.0010000000", "label": "CRV/USD" }, { "asset": "CRV", "currency": "XBT", "min_size": "2.5000000000", "increment": "0.0000001000", "label": "CRV/XBT" }, { "asset": "DAI", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "DAI/EUR" }, { "asset": "DAI", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "DAI/USD" }, { "asset": "DAI", "currency": "USDT", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "DAI/USDT" }, { "asset": "DASH", "currency": "EUR", "min_size": "0.0300000000", "increment": "0.0010000000", "label": "DASH/EUR" }, { "asset": "DASH", "currency": "USD", "min_size": "0.0300000000", "increment": "0.0010000000", "label": "DASH/USD" }, { "asset": "DASH", "currency": "XBT", "min_size": "0.0300000000", "increment": "0.0000100000", "label": "DASH/XBT" }, { "asset": "DOT", "currency": "AUD", "min_size": "0.2000000000", "increment": "0.0001000000", "label": "DOT/AUD" }, { "asset": "DOT", "currency": "ETH", "min_size": "0.2000000000", "increment": "0.0000010000", "label": "DOT/ETH" }, { "asset": "DOT", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0001000000", "label": "DOT/EUR" }, { "asset": "DOT", "currency": "GBP", "min_size": "0.2000000000", "increment": "0.0001000000", "label": "DOT/GBP" }, { "asset": "DOT", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0001000000", "label": "DOT/USD" }, { "asset": "DOT", "currency": "USDT", "min_size": "0.2000000000", "increment": "0.0001000000", "label": "DOT/USDT" }, { "asset": "DOT", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000000100", "label": "DOT/XBT" }, { "asset": "ENJ", "currency": "EUR", "min_size": "2.0000000000", "increment": "0.0010000000", "label": "ENJ/EUR" }, { "asset": "ENJ", "currency": "GBP", "min_size": "2.0000000000", "increment": "0.0010000000", "label": "ENJ/GBP" }, { "asset": "ENJ", "currency": "USD", "min_size": "2.0000000000", "increment": "0.0010000000", "label": "ENJ/USD" }, { "asset": "ENJ", "currency": "XBT", "min_size": "2.0000000000", "increment": "0.0000000100", "label": "ENJ/XBT" }, { "asset": "EOS", "currency": "ETH", "min_size": "1.0000000000", "increment": "0.0000010000", "label": "EOS/ETH" }, { "asset": "EOS", "currency": "EUR", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "EOS/EUR" }, { "asset": "EOS", "currency": "USD", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "EOS/USD" }, { "asset": "EOS", "currency": "USDT", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "EOS/USDT" }, { "asset": "EOS", "currency": "XBT", "min_size": "1.0000000000", "increment": "0.0000001000", "label": "EOS/XBT" }, { "asset": "ETH2.S", "currency": "ETH", "min_size": "0.0040000000", "increment": "0.0001000000", "label": "ETH2.S/ETH" }, { "asset": "ETH", "currency": "AUD", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/AUD" }, { "asset": "ETH", "currency": "CHF", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/CHF" }, { "asset": "ETH", "currency": "DAI", "min_size": "0.0040000000", "increment": "0.0010000000", "label": "ETH/DAI" }, { "asset": "ETH", "currency": "USDC", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/USDC" }, { "asset": "ETH", "currency": "USDT", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/USDT" }, { "asset": "EUR", "currency": "AUD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "EUR/AUD" }, { "asset": "EUR", "currency": "CAD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "EUR/CAD" }, { "asset": "EUR", "currency": "CHF", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "EUR/CHF" }, { "asset": "EUR", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "EUR/GBP" }, { "asset": "EUR", "currency": "JPY", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "EUR/JPY" }, { "asset": "EWT", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0010000000", "label": "EWT/EUR" }, { "asset": "EWT", "currency": "GBP", "min_size": "0.5000000000", "increment": "0.0010000000", "label": "EWT/GBP" }, { "asset": "EWT", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0010000000", "label": "EWT/USD" }, { "asset": "EWT", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000000100", "label": "EWT/XBT" }, { "asset": "FIL", "currency": "AUD", "min_size": "0.0500000000", "increment": "0.0010000000", "label": "FIL/AUD" }, { "asset": "FIL", "currency": "ETH", "min_size": "0.0500000000", "increment": "0.0000100000", "label": "FIL/ETH" }, { "asset": "FIL", "currency": "EUR", "min_size": "0.0500000000", "increment": "0.0010000000", "label": "FIL/EUR" }, { "asset": "FIL", "currency": "GBP", "min_size": "0.0500000000", "increment": "0.0010000000", "label": "FIL/GBP" }, { "asset": "FIL", "currency": "USD", "min_size": "0.0500000000", "increment": "0.0010000000", "label": "FIL/USD" }, { "asset": "FIL", "currency": "XBT", "min_size": "0.0500000000", "increment": "0.0000001000", "label": "FIL/XBT" }, { "asset": "FLOW", "currency": "ETH", "min_size": "0.2000000000", "increment": "0.0000100000", "label": "FLOW/ETH" }, { "asset": "FLOW", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "FLOW/EUR" }, { "asset": "FLOW", "currency": "GBP", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "FLOW/GBP" }, { "asset": "FLOW", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "FLOW/USD" }, { "asset": "FLOW", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000001000", "label": "FLOW/XBT" }, { "asset": "GHST", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "GHST/EUR" }, { "asset": "GHST", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "GHST/GBP" }, { "asset": "GHST", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "GHST/USD" }, { "asset": "GHST", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "GHST/XBT" }, { "asset": "GNO", "currency": "ETH", "min_size": "0.0500000000", "increment": "0.0001000000", "label": "GNO/ETH" }, { "asset": "GNO", "currency": "EUR", "min_size": "0.0500000000", "increment": "0.0100000000", "label": "GNO/EUR" }, { "asset": "GNO", "currency": "USD", "min_size": "0.0500000000", "increment": "0.0100000000", "label": "GNO/USD" }, { "asset": "GNO", "currency": "XBT", "min_size": "0.0500000000", "increment": "0.0000100000", "label": "GNO/XBT" }, { "asset": "GRT", "currency": "AUD", "min_size": "3.5000000000", "increment": "0.0000100000", "label": "GRT/AUD" }, { "asset": "GRT", "currency": "ETH", "min_size": "3.5000000000", "increment": "0.0000001000", "label": "GRT/ETH" }, { "asset": "GRT", "currency": "EUR", "min_size": "3.5000000000", "increment": "0.0000100000", "label": "GRT/EUR" }, { "asset": "GRT", "currency": "GBP", "min_size": "3.5000000000", "increment": "0.0000100000", "label": "GRT/GBP" }, { "asset": "GRT", "currency": "USD", "min_size": "3.5000000000", "increment": "0.0000100000", "label": "GRT/USD" }, { "asset": "GRT", "currency": "XBT", "min_size": "3.5000000000", "increment": "0.0000000100", "label": "GRT/XBT" }, { "asset": "ICX", "currency": "ETH", "min_size": "3.0000000000", "increment": "0.0000001000", "label": "ICX/ETH" }, { "asset": "ICX", "currency": "EUR", "min_size": "3.0000000000", "increment": "0.0001000000", "label": "ICX/EUR" }, { "asset": "ICX", "currency": "USD", "min_size": "3.0000000000", "increment": "0.0001000000", "label": "ICX/USD" }, { "asset": "ICX", "currency": "XBT", "min_size": "3.0000000000", "increment": "0.0000000100", "label": "ICX/XBT" }, { "asset": "KAVA", "currency": "ETH", "min_size": "1.0000000000", "increment": "0.0000010000", "label": "KAVA/ETH" }, { "asset": "KAVA", "currency": "EUR", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "KAVA/EUR" }, { "asset": "KAVA", "currency": "USD", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "KAVA/USD" }, { "asset": "KAVA", "currency": "XBT", "min_size": "1.0000000000", "increment": "0.0000000100", "label": "KAVA/XBT" }, { "asset": "KEEP", "currency": "ETH", "min_size": "10.0000000000", "increment": "0.0000001000", "label": "KEEP/ETH" }, { "asset": "KEEP", "currency": "EUR", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "KEEP/EUR" }, { "asset": "KEEP", "currency": "USD", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "KEEP/USD" }, { "asset": "KEEP", "currency": "XBT", "min_size": "10.0000000000", "increment": "0.0000000100", "label": "KEEP/XBT" }, { "asset": "KNC", "currency": "ETH", "min_size": "2.0000000000", "increment": "0.0000010000", "label": "KNC/ETH" }, { "asset": "KNC", "currency": "EUR", "min_size": "2.0000000000", "increment": "0.0001000000", "label": "KNC/EUR" }, { "asset": "KNC", "currency": "USD", "min_size": "2.0000000000", "increment": "0.0001000000", "label": "KNC/USD" }, { "asset": "KNC", "currency": "XBT", "min_size": "2.0000000000", "increment": "0.0000000100", "label": "KNC/XBT" }, { "asset": "KSM", "currency": "AUD", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "KSM/AUD" }, { "asset": "KSM", "currency": "DOT", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "KSM/DOT" }, { "asset": "KSM", "currency": "ETH", "min_size": "0.0200000000", "increment": "0.0000100000", "label": "KSM/ETH" }, { "asset": "KSM", "currency": "EUR", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "KSM/EUR" }, { "asset": "KSM", "currency": "GBP", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "KSM/GBP" }, { "asset": "KSM", "currency": "USD", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "KSM/USD" }, { "asset": "KSM", "currency": "XBT", "min_size": "0.0200000000", "increment": "0.0000010000", "label": "KSM/XBT" }, { "asset": "LINK", "currency": "AUD", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "LINK/AUD" }, { "asset": "LINK", "currency": "ETH", "min_size": "0.2000000000", "increment": "0.0000000100", "label": "LINK/ETH" }, { "asset": "LINK", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0000100000", "label": "LINK/EUR" }, { "asset": "LINK", "currency": "GBP", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "LINK/GBP" }, { "asset": "LINK", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0000100000", "label": "LINK/USD" }, { "asset": "LINK", "currency": "USDT", "min_size": "0.2000000000", "increment": "0.0000100000", "label": "LINK/USDT" }, { "asset": "LINK", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000000100", "label": "LINK/XBT" }, { "asset": "LPT", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "LPT/EUR" }, { "asset": "LPT", "currency": "GBP", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "LPT/GBP" }, { "asset": "LPT", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "LPT/USD" }, { "asset": "LPT", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000001000", "label": "LPT/XBT" }, { "asset": "LSK", "currency": "ETH", "min_size": "1.0000000000", "increment": "0.0000000100", "label": "LSK/ETH" }, { "asset": "LSK", "currency": "EUR", "min_size": "1.0000000000", "increment": "0.0000010000", "label": "LSK/EUR" }, { "asset": "LSK", "currency": "USD", "min_size": "1.0000000000", "increment": "0.0000010000", "label": "LSK/USD" }, { "asset": "LSK", "currency": "XBT", "min_size": "1.0000000000", "increment": "0.0000000010", "label": "LSK/XBT" }, { "asset": "LTC", "currency": "AUD", "min_size": "0.0300000000", "increment": "0.0100000000", "label": "LTC/AUD" }, { "asset": "LTC", "currency": "ETH", "min_size": "0.0300000000", "increment": "0.0000100000", "label": "LTC/ETH" }, { "asset": "LTC", "currency": "GBP", "min_size": "0.0300000000", "increment": "0.0000100000", "label": "LTC/GBP" }, { "asset": "LTC", "currency": "USDT", "min_size": "0.0300000000", "increment": "0.0000100000", "label": "LTC/USDT" }, { "asset": "MANA", "currency": "ETH", "min_size": "7.0000000000", "increment": "0.0000001000", "label": "MANA/ETH" }, { "asset": "MANA", "currency": "EUR", "min_size": "7.0000000000", "increment": "0.0000100000", "label": "MANA/EUR" }, { "asset": "MANA", "currency": "USD", "min_size": "7.0000000000", "increment": "0.0000100000", "label": "MANA/USD" }, { "asset": "MANA", "currency": "XBT", "min_size": "7.0000000000", "increment": "0.0000000100", "label": "MANA/XBT" }, { "asset": "MATIC", "currency": "EUR", "min_size": "20.0000000000", "increment": "0.0001000000", "label": "MATIC/EUR" }, { "asset": "MATIC", "currency": "GBP", "min_size": "20.0000000000", "increment": "0.0001000000", "label": "MATIC/GBP" }, { "asset": "MATIC", "currency": "USD", "min_size": "20.0000000000", "increment": "0.0001000000", "label": "MATIC/USD" }, { "asset": "MATIC", "currency": "XBT", "min_size": "20.0000000000", "increment": "0.0000000100", "label": "MATIC/XBT" }, { "asset": "MINA", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "MINA/EUR" }, { "asset": "MINA", "currency": "GBP", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "MINA/GBP" }, { "asset": "MINA", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0100000000", "label": "MINA/USD" }, { "asset": "MINA", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000001000", "label": "MINA/XBT" }, { "asset": "MKR", "currency": "EUR", "min_size": "0.0020000000", "increment": "0.1000000000", "label": "MKR/EUR" }, { "asset": "MKR", "currency": "GBP", "min_size": "0.0020000000", "increment": "0.1000000000", "label": "MKR/GBP" }, { "asset": "MKR", "currency": "USD", "min_size": "0.0020000000", "increment": "0.1000000000", "label": "MKR/USD" }, { "asset": "MKR", "currency": "XBT", "min_size": "0.0020000000", "increment": "0.0000100000", "label": "MKR/XBT" }, { "asset": "NANO", "currency": "ETH", "min_size": "1.5000000000", "increment": "0.0000000100", "label": "NANO/ETH" }, { "asset": "NANO", "currency": "EUR", "min_size": "1.5000000000", "increment": "0.0000010000", "label": "NANO/EUR" }, { "asset": "NANO", "currency": "USD", "min_size": "1.5000000000", "increment": "0.0000010000", "label": "NANO/USD" }, { "asset": "NANO", "currency": "XBT", "min_size": "1.5000000000", "increment": "0.0000000010", "label": "NANO/XBT" }, { "asset": "OCEAN", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "OCEAN/EUR" }, { "asset": "OCEAN", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "OCEAN/GBP" }, { "asset": "OCEAN", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "OCEAN/USD" }, { "asset": "OCEAN", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "OCEAN/XBT" }, { "asset": "OMG", "currency": "ETH", "min_size": "0.5000000000", "increment": "0.0000000100", "label": "OMG/ETH" }, { "asset": "OMG", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0000010000", "label": "OMG/EUR" }, { "asset": "OMG", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0000010000", "label": "OMG/USD" }, { "asset": "OMG", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000000010", "label": "OMG/XBT" }, { "asset": "OXT", "currency": "ETH", "min_size": "10.0000000000", "increment": "0.0000001000", "label": "OXT/ETH" }, { "asset": "OXT", "currency": "EUR", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "OXT/EUR" }, { "asset": "OXT", "currency": "USD", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "OXT/USD" }, { "asset": "OXT", "currency": "XBT", "min_size": "10.0000000000", "increment": "0.0000000100", "label": "OXT/XBT" }, { "asset": "PAXG", "currency": "ETH", "min_size": "0.0040000000", "increment": "0.0000010000", "label": "PAXG/ETH" }, { "asset": "PAXG", "currency": "EUR", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "PAXG/EUR" }, { "asset": "PAXG", "currency": "USD", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "PAXG/USD" }, { "asset": "PAXG", "currency": "XBT", "min_size": "0.0040000000", "increment": "0.0000010000", "label": "PAXG/XBT" }, { "asset": "QTUM", "currency": "ETH", "min_size": "0.5000000000", "increment": "0.0000001000", "label": "QTUM/ETH" }, { "asset": "QTUM", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0000100000", "label": "QTUM/EUR" }, { "asset": "QTUM", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0000100000", "label": "QTUM/USD" }, { "asset": "QTUM", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000001000", "label": "QTUM/XBT" }, { "asset": "RARI", "currency": "EUR", "min_size": "0.3000000000", "increment": "0.0100000000", "label": "RARI/EUR" }, { "asset": "RARI", "currency": "GBP", "min_size": "0.3000000000", "increment": "0.0100000000", "label": "RARI/GBP" }, { "asset": "RARI", "currency": "USD", "min_size": "0.3000000000", "increment": "0.0100000000", "label": "RARI/USD" }, { "asset": "RARI", "currency": "XBT", "min_size": "0.3000000000", "increment": "0.0000001000", "label": "RARI/XBT" }, { "asset": "REN", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "REN/EUR" }, { "asset": "REN", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "REN/GBP" }, { "asset": "REN", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "REN/USD" }, { "asset": "REN", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "REN/XBT" }, { "asset": "REPV2", "currency": "ETH", "min_size": "0.1500000000", "increment": "0.0000100000", "label": "REPV2/ETH" }, { "asset": "REPV2", "currency": "EUR", "min_size": "0.1500000000", "increment": "0.0010000000", "label": "REPV2/EUR" }, { "asset": "REPV2", "currency": "USD", "min_size": "0.1500000000", "increment": "0.0010000000", "label": "REPV2/USD" }, { "asset": "REPV2", "currency": "XBT", "min_size": "0.1500000000", "increment": "0.0000010000", "label": "REPV2/XBT" }, { "asset": "SAND", "currency": "EUR", "min_size": "10.0000000000", "increment": "0.0001000000", "label": "SAND/EUR" }, { "asset": "SAND", "currency": "GBP", "min_size": "10.0000000000", "increment": "0.0001000000", "label": "SAND/GBP" }, { "asset": "SAND", "currency": "USD", "min_size": "10.0000000000", "increment": "0.0001000000", "label": "SAND/USD" }, { "asset": "SAND", "currency": "XBT", "min_size": "10.0000000000", "increment": "0.0000000100", "label": "SAND/XBT" }, { "asset": "SC", "currency": "ETH", "min_size": "280.0000000000", "increment": "0.0000000100", "label": "SC/ETH" }, { "asset": "SC", "currency": "EUR", "min_size": "280.0000000000", "increment": "0.0000100000", "label": "SC/EUR" }, { "asset": "SC", "currency": "USD", "min_size": "280.0000000000", "increment": "0.0000100000", "label": "SC/USD" }, { "asset": "SC", "currency": "XBT", "min_size": "280.0000000000", "increment": "0.0000000001", "label": "SC/XBT" }, { "asset": "SNX", "currency": "AUD", "min_size": "0.4000000000", "increment": "0.0010000000", "label": "SNX/AUD" }, { "asset": "SNX", "currency": "ETH", "min_size": "0.4000000000", "increment": "0.0000100000", "label": "SNX/ETH" }, { "asset": "SNX", "currency": "EUR", "min_size": "0.4000000000", "increment": "0.0010000000", "label": "SNX/EUR" }, { "asset": "SNX", "currency": "GBP", "min_size": "0.4000000000", "increment": "0.0010000000", "label": "SNX/GBP" }, { "asset": "SNX", "currency": "USD", "min_size": "0.4000000000", "increment": "0.0010000000", "label": "SNX/USD" }, { "asset": "SNX", "currency": "XBT", "min_size": "0.4000000000", "increment": "0.0000001000", "label": "SNX/XBT" }, { "asset": "STORJ", "currency": "ETH", "min_size": "3.0000000000", "increment": "0.0000001000", "label": "STORJ/ETH" }, { "asset": "STORJ", "currency": "EUR", "min_size": "3.0000000000", "increment": "0.0000100000", "label": "STORJ/EUR" }, { "asset": "STORJ", "currency": "USD", "min_size": "3.0000000000", "increment": "0.0000100000", "label": "STORJ/USD" }, { "asset": "STORJ", "currency": "XBT", "min_size": "3.0000000000", "increment": "0.0000000010", "label": "STORJ/XBT" }, { "asset": "SUSHI", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0100000000", "label": "SUSHI/EUR" }, { "asset": "SUSHI", "currency": "GBP", "min_size": "0.5000000000", "increment": "0.0100000000", "label": "SUSHI/GBP" }, { "asset": "SUSHI", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0100000000", "label": "SUSHI/USD" }, { "asset": "SUSHI", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000001000", "label": "SUSHI/XBT" }, { "asset": "TBTC", "currency": "ETH", "min_size": "0.0001000000", "increment": "0.0010000000", "label": "TBTC/ETH" }, { "asset": "TBTC", "currency": "EUR", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "TBTC/EUR" }, { "asset": "TBTC", "currency": "USD", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "TBTC/USD" }, { "asset": "TBTC", "currency": "XBT", "min_size": "0.0001000000", "increment": "0.0000100000", "label": "TBTC/XBT" }, { "asset": "TRX", "currency": "ETH", "min_size": "50.0000000000", "increment": "0.0000000100", "label": "TRX/ETH" }, { "asset": "TRX", "currency": "EUR", "min_size": "50.0000000000", "increment": "0.0000010000", "label": "TRX/EUR" }, { "asset": "TRX", "currency": "USD", "min_size": "50.0000000000", "increment": "0.0000010000", "label": "TRX/USD" }, { "asset": "TRX", "currency": "XBT", "min_size": "50.0000000000", "increment": "0.0000000001", "label": "TRX/XBT" }, { "asset": "UNI", "currency": "ETH", "min_size": "0.2000000000", "increment": "0.0000100000", "label": "UNI/ETH" }, { "asset": "UNI", "currency": "EUR", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "UNI/EUR" }, { "asset": "UNI", "currency": "USD", "min_size": "0.2000000000", "increment": "0.0010000000", "label": "UNI/USD" }, { "asset": "UNI", "currency": "XBT", "min_size": "0.2000000000", "increment": "0.0000001000", "label": "UNI/XBT" }, { "asset": "USDC", "currency": "AUD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDC/AUD" }, { "asset": "USDC", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDC/EUR" }, { "asset": "USDC", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDC/GBP" }, { "asset": "USD", "currency": "CHF", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "USD/CHF" }, { "asset": "USDC", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDC/USD" }, { "asset": "USDC", "currency": "USDT", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDC/USDT" }, { "asset": "USDT", "currency": "AUD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDT/AUD" }, { "asset": "USDT", "currency": "CAD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDT/CAD" }, { "asset": "USDT", "currency": "CHF", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "USDT/CHF" }, { "asset": "USDT", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDT/EUR" }, { "asset": "USDT", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDT/GBP" }, { "asset": "USDT", "currency": "JPY", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "USDT/JPY" }, { "asset": "USDT", "currency": "ZUSD", "min_size": "5.0000000000", "increment": "0.0001000000", "label": "USDT/USD" }, { "asset": "WAVES", "currency": "ETH", "min_size": "0.5000000000", "increment": "0.0000001000", "label": "WAVES/ETH" }, { "asset": "WAVES", "currency": "EUR", "min_size": "0.5000000000", "increment": "0.0001000000", "label": "WAVES/EUR" }, { "asset": "WAVES", "currency": "USD", "min_size": "0.5000000000", "increment": "0.0001000000", "label": "WAVES/USD" }, { "asset": "WAVES", "currency": "XBT", "min_size": "0.5000000000", "increment": "0.0000000100", "label": "WAVES/XBT" }, { "asset": "XBT", "currency": "AUD", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/AUD" }, { "asset": "XBT", "currency": "CHF", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/CHF" }, { "asset": "XBT", "currency": "DAI", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/DAI" }, { "asset": "XBT", "currency": "USDC", "min_size": "0.0001000000", "increment": "0.0100000000", "label": "XBT/USDC" }, { "asset": "XBT", "currency": "USDT", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/USDT" }, { "asset": "XDG", "currency": "EUR", "min_size": "50.0000000000", "increment": "0.0000001000", "label": "XDG/EUR" }, { "asset": "XDG", "currency": "USD", "min_size": "50.0000000000", "increment": "0.0000001000", "label": "XDG/USD" }, { "asset": "XDG", "currency": "USDT", "min_size": "50.0000000000", "increment": "0.0000100000", "label": "XDG/USDT" }, { "asset": "XETC", "currency": "XETH", "min_size": "0.3500000000", "increment": "0.0000010000", "label": "ETC/ETH" }, { "asset": "XETC", "currency": "XXBT", "min_size": "0.3500000000", "increment": "0.0000010000", "label": "ETC/XBT" }, { "asset": "XETC", "currency": "ZEUR", "min_size": "0.3500000000", "increment": "0.0010000000", "label": "ETC/EUR" }, { "asset": "XETC", "currency": "ZUSD", "min_size": "0.3500000000", "increment": "0.0010000000", "label": "ETC/USD" }, { "asset": "XETH", "currency": "XXBT", "min_size": "0.0040000000", "increment": "0.0000100000", "label": "ETH/XBT" }, { "asset": "XETH", "currency": "ZCAD", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/CAD" }, { "asset": "XETH", "currency": "ZEUR", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/EUR" }, { "asset": "XETH", "currency": "ZGBP", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/GBP" }, { "asset": "XETH", "currency": "ZJPY", "min_size": "0.0040000000", "increment": "1.0000000000", "label": "ETH/JPY" }, { "asset": "XETH", "currency": "ZUSD", "min_size": "0.0040000000", "increment": "0.0100000000", "label": "ETH/USD" }, { "asset": "XLTC", "currency": "XXBT", "min_size": "0.0300000000", "increment": "0.0000010000", "label": "LTC/XBT" }, { "asset": "XLTC", "currency": "ZEUR", "min_size": "0.0300000000", "increment": "0.0100000000", "label": "LTC/EUR" }, { "asset": "XLTC", "currency": "ZJPY", "min_size": "0.0300000000", "increment": "1.0000000000", "label": "LTC/JPY" }, { "asset": "XLTC", "currency": "ZUSD", "min_size": "0.0300000000", "increment": "0.0100000000", "label": "LTC/USD" }, { "asset": "XMLN", "currency": "XETH", "min_size": "0.1000000000", "increment": "0.0000100000", "label": "MLN/ETH" }, { "asset": "XMLN", "currency": "XXBT", "min_size": "0.1000000000", "increment": "0.0000010000", "label": "MLN/XBT" }, { "asset": "XMLN", "currency": "ZEUR", "min_size": "0.1000000000", "increment": "0.0010000000", "label": "MLN/EUR" }, { "asset": "XMLN", "currency": "ZUSD", "min_size": "0.1000000000", "increment": "0.0010000000", "label": "MLN/USD" }, { "asset": "XREP", "currency": "XETH", "min_size": "0.1500000000", "increment": "0.0000100000", "label": "REP/ETH" }, { "asset": "XREP", "currency": "XXBT", "min_size": "0.1500000000", "increment": "0.0000010000", "label": "REP/XBT" }, { "asset": "XREP", "currency": "ZEUR", "min_size": "0.1500000000", "increment": "0.0010000000", "label": "REP/EUR" }, { "asset": "XREP", "currency": "ZUSD", "min_size": "0.1500000000", "increment": "0.0010000000", "label": "REP/USD" }, { "asset": "XRP", "currency": "AUD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/AUD" }, { "asset": "XRP", "currency": "ETH", "min_size": "5.0000000000", "increment": "0.0000001000", "label": "XRP/ETH" }, { "asset": "XRP", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/GBP" }, { "asset": "XRP", "currency": "USDT", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/USDT" }, { "asset": "XTZ", "currency": "AUD", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "XTZ/AUD" }, { "asset": "XTZ", "currency": "ETH", "min_size": "1.0000000000", "increment": "0.0000001000", "label": "XTZ/ETH" }, { "asset": "XTZ", "currency": "EUR", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "XTZ/EUR" }, { "asset": "XTZ", "currency": "GBP", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "XTZ/GBP" }, { "asset": "XTZ", "currency": "USD", "min_size": "1.0000000000", "increment": "0.0001000000", "label": "XTZ/USD" }, { "asset": "XTZ", "currency": "XBT", "min_size": "1.0000000000", "increment": "0.0000001000", "label": "XTZ/XBT" }, { "asset": "XXBT", "currency": "ZCAD", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/CAD" }, { "asset": "XXBT", "currency": "ZEUR", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/EUR" }, { "asset": "XXBT", "currency": "ZGBP", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/GBP" }, { "asset": "XXBT", "currency": "ZJPY", "min_size": "0.0001000000", "increment": "1.0000000000", "label": "XBT/JPY" }, { "asset": "XXBT", "currency": "ZUSD", "min_size": "0.0001000000", "increment": "0.1000000000", "label": "XBT/USD" }, { "asset": "XXDG", "currency": "XXBT", "min_size": "50.0000000000", "increment": "0.0000000100", "label": "XDG/XBT" }, { "asset": "XXLM", "currency": "XXBT", "min_size": "10.0000000000", "increment": "0.0000000100", "label": "XLM/XBT" }, { "asset": "XXLM", "currency": "ZAUD", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "XLM/AUD" }, { "asset": "XXLM", "currency": "ZEUR", "min_size": "10.0000000000", "increment": "0.0000010000", "label": "XLM/EUR" }, { "asset": "XXLM", "currency": "ZGBP", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "XLM/GBP" }, { "asset": "XXLM", "currency": "ZUSD", "min_size": "10.0000000000", "increment": "0.0000010000", "label": "XLM/USD" }, { "asset": "XXMR", "currency": "XXBT", "min_size": "0.0200000000", "increment": "0.0000010000", "label": "XMR/XBT" }, { "asset": "XXMR", "currency": "ZEUR", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "XMR/EUR" }, { "asset": "XXMR", "currency": "ZUSD", "min_size": "0.0200000000", "increment": "0.0100000000", "label": "XMR/USD" }, { "asset": "XXRP", "currency": "XXBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "XRP/XBT" }, { "asset": "XXRP", "currency": "ZCAD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/CAD" }, { "asset": "XXRP", "currency": "ZEUR", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/EUR" }, { "asset": "XXRP", "currency": "ZJPY", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "XRP/JPY" }, { "asset": "XXRP", "currency": "ZUSD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "XRP/USD" }, { "asset": "XZEC", "currency": "XXBT", "min_size": "0.0350000000", "increment": "0.0000100000", "label": "ZEC/XBT" }, { "asset": "XZEC", "currency": "ZEUR", "min_size": "0.0350000000", "increment": "0.0010000000", "label": "ZEC/EUR" }, { "asset": "XZEC", "currency": "ZUSD", "min_size": "0.0350000000", "increment": "0.0100000000", "label": "ZEC/USD" }, { "asset": "YFI", "currency": "AUD", "min_size": "0.0001500000", "increment": "1.0000000000", "label": "YFI/AUD" }, { "asset": "YFI", "currency": "ETH", "min_size": "0.0001500000", "increment": "0.0100000000", "label": "YFI/ETH" }, { "asset": "YFI", "currency": "EUR", "min_size": "0.0001500000", "increment": "1.0000000000", "label": "YFI/EUR" }, { "asset": "YFI", "currency": "GBP", "min_size": "0.0001500000", "increment": "1.0000000000", "label": "YFI/GBP" }, { "asset": "YFI", "currency": "USD", "min_size": "0.0001500000", "increment": "1.0000000000", "label": "YFI/USD" }, { "asset": "YFI", "currency": "XBT", "min_size": "0.0001500000", "increment": "0.0001000000", "label": "YFI/XBT" }, { "asset": "ZEUR", "currency": "ZUSD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "EUR/USD" }, { "asset": "ZGBP", "currency": "ZUSD", "min_size": "5.0000000000", "increment": "0.0000100000", "label": "GBP/USD" }, { "asset": "ZRX", "currency": "EUR", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "ZRX/EUR" }, { "asset": "ZRX", "currency": "GBP", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "ZRX/GBP" }, { "asset": "ZRX", "currency": "USD", "min_size": "5.0000000000", "increment": "0.0010000000", "label": "ZRX/USD" }, { "asset": "ZRX", "currency": "XBT", "min_size": "5.0000000000", "increment": "0.0000000100", "label": "ZRX/XBT" }, { "asset": "ZUSD", "currency": "ZCAD", "min_size": "10.0000000000", "increment": "0.0000100000", "label": "USD/CAD" }, { "asset": "ZUSD", "currency": "ZJPY", "min_size": "10.0000000000", "increment": "0.0010000000", "label": "USD/JPY" } ] ================================================ FILE: extensions/exchanges/kraken/update-products.sh ================================================ #!/usr/bin/env node var KrakenClient = require('kraken-api') var kraken = new KrakenClient() var products = [] function addProduct (base, quote, label, min_size, increment) { products.push({ asset: base, currency: quote, min_size: parseFloat(min_size).toFixed(10), increment: (10 ** (-1 * increment)).toFixed(10), label: label }) } kraken.api('AssetPairs', null, function (error, data) { if (error) { console.log(error) process.exit(1) } else { Object.keys(data.result).forEach(function (pair) { if (!pair.match('.d')) { if (!data.result[pair].wsname) { console.warn(`Cannot identify pair for ${pair}`) return } const wsname = data.result[pair].wsname const split = wsname.split('/') const asset = pair.substring(0, pair.indexOf(split[0]) + split[0].length) const currency = pair.substring(asset.length) addProduct(asset, currency, wsname, data.result[pair].ordermin, data.result[pair].pair_decimals) } }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() } }) ================================================ FILE: extensions/exchanges/poloniex/exchange.js ================================================ var Poloniex = require('poloniex.js') , moment = require('moment') , n = require('numbro') // eslint-disable-next-line no-unused-vars , colors = require('colors') module.exports = function container (conf) { var public_client, authed_client function publicClient (/*product_id*/) { if (!public_client) public_client = new Poloniex() return public_client } function authedClient () { if (!authed_client) { if (!conf.poloniex || !conf.poloniex.key || conf.poloniex.key === 'YOUR-API-KEY') { throw new Error('please configure your Poloniex credentials in conf.js') } authed_client = new Poloniex(conf.poloniex.key, conf.poloniex.secret) } return authed_client } function joinProduct (product_id) { return product_id.split('-')[1] + '_' + product_id.split('-')[0] } function retry (method, args) { setTimeout(function () { exchange[method].apply(exchange, args) }, 1) } var orders = {} var exchange = { name: 'poloniex', historyScan: 'backward', makerFee: 0.15, takerFee: 0.25, offset: 43200, getProducts: function () { return require('./products.json') }, getTrades: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() var args = { currencyPair: joinProduct(opts.product_id) } if (opts.from) { args.start = opts.from } if (opts.to) { args.end = opts.to } if (args.start && !args.end) { // add 12 hours args.end = args.start + (opts.offset || this.offset) } else if (args.end && !args.start) { // subtract 12 hours args.start = args.end - (opts.offset || this.offset) } client._public('returnTradeHistory', args, function (err, body) { if (err) return cb(err) if (typeof body === 'string') { return retry('getTrades', func_args) } if (!body.map) { console.error('\ngetTrades odd result:') console.error(body) return retry('getTrades', func_args) } if (body.length >= 50000) { func_args[0].offset = opts.offset / 2; return retry('getTrades', func_args) } var trades = body.map(function (trade) { return { trade_id: trade.tradeID, time: moment.utc(trade.date).valueOf(), size: Number(trade.amount), price: Number(trade.rate), side: trade.type } }) cb(null, trades) }) }, getBalance: function (opts, cb) { var args = [].slice.call(arguments) var client = authedClient() client.returnCompleteBalances(function (err, body) { if (err) return cb(err) var balance = {asset: 0, currency: 0} if (typeof body === 'string') { return retry('getBalance', args) } if (body.error) { console.error('\ngetBalance error:') console.error(body) return retry('getBalance', args) } if (body[opts.currency]) { balance.currency = n(body[opts.currency].available).add(body[opts.currency].onOrders).format('0.00000000') balance.currency_hold = body[opts.currency].onOrders } if (body[opts.asset]) { balance.asset = n(body[opts.asset].available).add(body[opts.asset].onOrders).format('0.00000000') balance.asset_hold = body[opts.asset].onOrders } cb(null, balance) }) }, getOrderBook: function (opts, cb) { var client = publicClient() var params = { currencyPair: joinProduct(opts.product_id), depth: 10 } client._public('returnOrderBook', params, function (err, data) { if (typeof data !== 'object') { return cb(null, []) } if (data.error) { console.error('getOrderBook error:') console.error(data) return retry('getOrderBook', params) } cb(null, { buyOrderRate: data.bids[0][0], buyOrderAmount: data.bids[0][1], sellOrderRate: data.asks[0][0], sellOrderAmount: data.asks[0][1] }) }) }, getQuote: function (opts, cb) { var args = [].slice.call(arguments) var client = publicClient() var product_id = joinProduct(opts.product_id) client.getTicker(function (err, body) { if (err) return cb(err) if (typeof body === 'string') { return retry('getQuote', args) } if (body.error) { console.error('\ngetQuote error:') console.error(body) return retry('getQuote', args) } var quote = body[product_id] if (!quote) return cb(new Error('no quote for ' + product_id)) if (quote.isFrozen == '1') console.error('\nwarning: product ' + product_id + ' is frozen') cb(null, { bid: quote.highestBid, ask: quote.lowestAsk, }) }) }, cancelOrder: function (opts, cb) { var args = [].slice.call(arguments) var client = authedClient() client._private('cancelOrder', {orderNumber: opts.order_id}, function (err, result) { if (typeof result === 'string') { return retry('cancelOrder', args) } if (!err && !result.success) { // sometimes the order gets cancelled on the server side for some reason and we get this. ignore that case... if (result.error !== 'Invalid order number, or you are not the person who placed the order.') { err = new Error('unable to cancel order') err.body = result } } cb(err) }) }, trade: function (type, opts, cb) { var args = [].slice.call(arguments) var client = authedClient() var params = { currencyPair: joinProduct(opts.product_id), rate: opts.price, amount: opts.size, postOnly: opts.post_only === false ? '0' : '1' } client._private(type, params, function (err, result) { if (typeof result === 'string') { return retry('trade', args) } var order = { id: result ? result.orderNumber : null, status: 'open', price: opts.price, size: opts.size, post_only: !!opts.post_only, created_at: new Date().getTime(), filled_size: '0' } if (result && result.error === 'Unable to place post-only order at this price.') { order.status = 'rejected' order.reject_reason = 'post only' return cb(null, order) } else if (result && result.error && result.error.match(/^Not enough/)) { order.status = 'rejected' order.reject_reason = 'balance' return cb(null, order) } else if (result && result.error && result.error.match(/^Nonce must be greater/)) { return retry('trade', args) } if (!err && result.error) { err = new Error('unable to ' + type) err.body = result } if (err) return cb(err) orders['~' + result.orderNumber] = order cb(null, order) }) }, buy: function (opts, cb) { exchange.trade('buy', opts, cb) }, sell: function (opts, cb) { exchange.trade('sell', opts, cb) }, getOrder: function (opts, cb) { var args = [].slice.call(arguments) var order = orders['~' + opts.order_id] if (!order) return cb(new Error('order not found in cache')) var client = authedClient() var params = { currencyPair: joinProduct(opts.product_id) } client._private('returnOpenOrders', params, function (err, body) { if (err) return cb(err) if (typeof body === 'string' || !body) { return retry('getOrder', args) } var active = false if (!body.forEach) { console.error('\nreturnOpenOrders odd result in checking state of order, trying again') //console.error(body) return retry('getOrder', args) } else { body.forEach(function (api_order) { if (api_order.orderNumber == opts.order_id) active = true }) } client.returnOrderTrades(opts.order_id, function (err, body) { if (typeof body === 'string' || !body) { return retry('getOrder', args) } if (err || body.error || !body.forEach) return cb(null, order) if (body.length === 0 && !active) { order.status = 'cancelled' return cb(null, order) } order.filled_size = '0' body.forEach(function (trade) { order.filled_size = n(order.filled_size).add(trade.amount).format('0.00000000') }) if (n(order.filled_size).value() == n(order.size).value()) { order.status = 'done' order.done_at = new Date().getTime() } cb(null, order) }) }) }, // return the property used for range querying. getCursor: function (trade) { return Math.floor((trade.time || trade) / 1000) } } return exchange } ================================================ FILE: extensions/exchanges/poloniex/products.json ================================================ [ { "asset": "AAVE", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Aave/Bitcoin" }, { "asset": "AAVE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Aave/Tether USD" }, { "asset": "ADABEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Cardano Token/Tether USD" }, { "asset": "ADABULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Cardano Token/Tether USD" }, { "asset": "ADD", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "ADD/Tether USD" }, { "asset": "ADEL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Akropolis Delphi/Tether USD" }, { "asset": "AKITA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Akita Inu/Tether USD" }, { "asset": "AKRO", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Akropolis/Bitcoin" }, { "asset": "AKRO", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Akropolis/Tether USD" }, { "asset": "ALPHA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Alpha Finance/Tether USD" }, { "asset": "AMP", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Amp/Bitcoin" }, { "asset": "AMP", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Amp/Tron" }, { "asset": "AMP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Amp/Tether USD" }, { "asset": "API3", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "API3/Tether USD" }, { "asset": "ARDR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ardor/Bitcoin" }, { "asset": "ATOM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Cosmos/Bitcoin" }, { "asset": "ATOM", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Cosmos/USD Coin" }, { "asset": "ATOM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Cosmos/Tether USD" }, { "asset": "AVA", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Travala.com Token/Bitcoin" }, { "asset": "AVA", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Travala.com Token/Tron" }, { "asset": "AVA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Travala.com Token/Tether USD" }, { "asset": "B20", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "B20/Tether USD" }, { "asset": "BAC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Basis Cash/Tether USD" }, { "asset": "BADGER", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Badger DAO/Tether USD" }, { "asset": "BAL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Balancer/Tether USD" }, { "asset": "BAND", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Band Protocol Token/Tether USD" }, { "asset": "BAT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Basic Attention Token/Bitcoin" }, { "asset": "BAT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Basic Attention Token/Tether USD" }, { "asset": "BCH", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Cash/Bitcoin" }, { "asset": "BCH", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Cash/USD Coin" }, { "asset": "BCH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Cash/Tether USD" }, { "asset": "BCHA", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Cash ABC/Bitcoin" }, { "asset": "BCHA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Cash ABC/Tether USD" }, { "asset": "BCHBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Bitcoin Cash Token/Tether USD" }, { "asset": "BCHBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Bitcoin Cash Token/Tether USD" }, { "asset": "BCHC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "BitCherry/Tether USD" }, { "asset": "BCHSV", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin SV/Bitcoin" }, { "asset": "BCHSV", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin SV/USD Coin" }, { "asset": "BCHSV", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin SV/Tether USD" }, { "asset": "BCN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bytecoin/Tether USD" }, { "asset": "BDP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Big Data Protocol/Tether USD" }, { "asset": "BEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Bitcoin Token/Tether USD" }, { "asset": "BID", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bidao/Bitcoin" }, { "asset": "BID", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bidao/Tether USD" }, { "asset": "BLY", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Blocery/Tether USD" }, { "asset": "BNB", "currency": "BUSD", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Binance Coin/Binance USD" }, { "asset": "BNB", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Binance Coin/Tron" }, { "asset": "BNB", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Binance Coin/Tether USD" }, { "asset": "BNT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bancor/Bitcoin" }, { "asset": "BOND", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "BarnBridge/Tether USD" }, { "asset": "BRG", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bridge Oracle/Tron" }, { "asset": "BRG", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bridge Oracle/Tether USD" }, { "asset": "BSVBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Bitcoin SV Token/Tether USD" }, { "asset": "BSVBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Bitcoin SV Token/Tether USD" }, { "asset": "BTC", "currency": "BNB", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/Binance Coin" }, { "asset": "BTC", "currency": "BUSD", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/Binance USD" }, { "asset": "BTC", "currency": "DAI", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/Dai Stablecoin" }, { "asset": "BTC", "currency": "PAX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/Paxos Standard" }, { "asset": "BTC", "currency": "TUSD", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/TrueUSD" }, { "asset": "BTC", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/USD Coin" }, { "asset": "BTC", "currency": "USDJ", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/USDJ" }, { "asset": "BTC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin/Tether USD" }, { "asset": "BTCST", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Standard Hashrate Token/Tether USD" }, { "asset": "BTS", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "BitShares/Bitcoin" }, { "asset": "BTT", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "BitTorrent/Tron" }, { "asset": "BTT", "currency": "USDJ", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "BitTorrent/USDJ" }, { "asset": "BTT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "BitTorrent/Tether USD" }, { "asset": "BULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Bitcoin Token/Tether USD" }, { "asset": "BUSD", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Binance USD/Tether USD" }, { "asset": "BVOL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Bitcoin Volatility Token/Tether USD" }, { "asset": "BZRX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "bZx Protocol Token/Tether USD" }, { "asset": "CHR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Chromia/Bitcoin" }, { "asset": "CHR", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Chromia/Tron" }, { "asset": "CHR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Chromia/Tether USD" }, { "asset": "COMBO", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Furucombo/Tether USD" }, { "asset": "COMP", "currency": "ETH", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Compound Governance Token/Ethereum" }, { "asset": "COMP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Compound Governance Token/Tether USD" }, { "asset": "CORN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Corn/Tether USD" }, { "asset": "CREAM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Cream/Tether USD" }, { "asset": "CRV", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Curve Finance/Tether USD" }, { "asset": "CTSI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Cartesi Token /Tether USD" }, { "asset": "CUDOS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "CudosToken/Tether USD" }, { "asset": "CUSDT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Compound USDT/Tether USD" }, { "asset": "CVC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Civic/Bitcoin" }, { "asset": "CVP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "PowerPool Concentrated Vot Power/Tether USD" }, { "asset": "CVT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "CyberVeinToken/Bitcoin" }, { "asset": "CVT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "CyberVeinToken/Tether USD" }, { "asset": "DAI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Dai Stablecoin/Tether USD" }, { "asset": "DASH", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Dash/Bitcoin" }, { "asset": "DASH", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Dash/USD Coin" }, { "asset": "DASH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Dash/Tether USD" }, { "asset": "DCR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Decred/Bitcoin" }, { "asset": "DEC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Decentr/Tether USD" }, { "asset": "DEGO", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Dego Finance/Tether USD" }, { "asset": "DEXT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "DexTools/Tether USD" }, { "asset": "DHT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "dHedge DAO/Tether USD" }, { "asset": "DIA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "DIA/Tether USD" }, { "asset": "DICE", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "TRONbetDice/Tron" }, { "asset": "DICE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "TRONbetDice/Tether USD" }, { "asset": "DOGE", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Dogecoin/Bitcoin" }, { "asset": "DOGE", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Dogecoin/USD Coin" }, { "asset": "DOGE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Dogecoin/Tether USD" }, { "asset": "DOS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "DOS Network/Tether USD" }, { "asset": "DOT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Polkadot/Bitcoin" }, { "asset": "DOT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Polkadot/Tether USD" }, { "asset": "ELON", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Dogelon/Tether USD" }, { "asset": "EOS", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "EOS/Bitcoin" }, { "asset": "EOS", "currency": "ETH", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "EOS/Ethereum" }, { "asset": "EOS", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "EOS/USD Coin" }, { "asset": "EOS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "EOS/Tether USD" }, { "asset": "EOSBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short EOS Token/Tether USD" }, { "asset": "EOSBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long EOS Token/Tether USD" }, { "asset": "ESD", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Empty Set Dollar/Tether USD" }, { "asset": "ETC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum Classic/Bitcoin" }, { "asset": "ETC", "currency": "ETH", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum Classic/Ethereum" }, { "asset": "ETC", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum Classic/USD Coin" }, { "asset": "ETC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Ethereum Classic/Tether USD" }, { "asset": "ETH", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/Bitcoin" }, { "asset": "ETH", "currency": "DAI", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/Dai Stablecoin" }, { "asset": "ETH", "currency": "PAX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/Paxos Standard" }, { "asset": "ETH", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/Tron" }, { "asset": "ETH", "currency": "TUSD", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/TrueUSD" }, { "asset": "ETH", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ethereum/USD Coin" }, { "asset": "ETH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Ethereum/Tether USD" }, { "asset": "ETHBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Ethereum Token/Tether USD" }, { "asset": "ETHBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Ethereum Token/Tether USD" }, { "asset": "EXE", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "8X8 Protocol/Bitcoin" }, { "asset": "EXE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "8X8 Protocol/Tether USD" }, { "asset": "FARM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Harvest Finance/Bitcoin" }, { "asset": "FARM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Harvest Finance/Tether USD" }, { "asset": "FCT2", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Firmachain/Bitcoin" }, { "asset": "FCT2", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Firmachain/Tether USD" }, { "asset": "FIL", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Filecoin/Bitcoin" }, { "asset": "FIL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Filecoin/Tether USD" }, { "asset": "FOAM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Foam/Bitcoin" }, { "asset": "FORTH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Ampleforth Governance Token/Tether USD" }, { "asset": "FRONT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Frontier/Bitcoin" }, { "asset": "FRONT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Frontier/Tether USD" }, { "asset": "FSW", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "FalconSwap/Tether USD" }, { "asset": "FTT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "FTX Token/Tether USD" }, { "asset": "FUND", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Unification/Bitcoin" }, { "asset": "FUND", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Unification/Tron" }, { "asset": "FUND", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Unification/Tether USD" }, { "asset": "GAS", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Gas/Bitcoin" }, { "asset": "GEEQ", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "GEEQ/Tether USD" }, { "asset": "GHST", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Aavegotchi/Tether USD" }, { "asset": "GLM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Golem Network Token/Bitcoin" }, { "asset": "GLM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Golem Network Token/Tether USD" }, { "asset": "GRT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "The Graph/Tether USD" }, { "asset": "GTC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Gitcoin/Tether USD" }, { "asset": "HEGIC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Hegic/Tether USD" }, { "asset": "HGET", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Hedget/Bitcoin" }, { "asset": "HGET", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Hedget/Tether USD" }, { "asset": "HT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Huobi Token/Tether USD" }, { "asset": "IBVOL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Inverse Bitcoin Volatility Token/Tether USD" }, { "asset": "INJ", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Injective Protocol/Bitcoin" }, { "asset": "INJ", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Injective Protocol/Tether USD" }, { "asset": "JFI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "JackPool.finance/Tether USD" }, { "asset": "JST", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Just/Tron" }, { "asset": "JST", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Just/Tether USD" }, { "asset": "KCS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "KuCoin Token/Tether USD" }, { "asset": "KISHU", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Kishu Inu /Tron" }, { "asset": "KLV", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Klever/Bitcoin" }, { "asset": "KLV", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Klever/Tron" }, { "asset": "KLV", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Klever/Tether USD" }, { "asset": "KNC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Kyber/Bitcoin" }, { "asset": "KP3R", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Keep3rV1/Tether USD" }, { "asset": "KTON", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Darwinia Commitment Token/Tether USD" }, { "asset": "LINK", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Chainlink/Bitcoin" }, { "asset": "LINK", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Chainlink/Tron" }, { "asset": "LINK", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Chainlink/Tether USD" }, { "asset": "LINKBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Chainlink Token/Tether USD" }, { "asset": "LINKBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Chainlink Token/Tether USD" }, { "asset": "LIVE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "TRONbetLive/Tether USD" }, { "asset": "LON", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tokenlon/Tether USD" }, { "asset": "LOOM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "LOOM Network/Bitcoin" }, { "asset": "LPT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Livepeer/Bitcoin" }, { "asset": "LPT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Livepeer/Tether USD" }, { "asset": "LQTY", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "LQTY/Tether USD" }, { "asset": "LRC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Loopring/Bitcoin" }, { "asset": "LRC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Loopring/Tether USD" }, { "asset": "LSK", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Lisk/Bitcoin" }, { "asset": "LSK", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Lisk/Tether USD" }, { "asset": "LTC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Litecoin/Bitcoin" }, { "asset": "LTC", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Litecoin/USD Coin" }, { "asset": "LTC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Litecoin/Tether USD" }, { "asset": "LTCBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Litecoin Token/Tether USD" }, { "asset": "LTCBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Litecoin Token/Tether USD" }, { "asset": "LUSD", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "LUSD Stablecoin/Tether USD" }, { "asset": "MANA", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Decentraland/Bitcoin" }, { "asset": "MANA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Decentraland/Tether USD" }, { "asset": "MATIC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Polygon/Bitcoin" }, { "asset": "MATIC", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Polygon/Tron" }, { "asset": "MATIC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Polygon/Tether USD" }, { "asset": "MCB", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "MCDex/Tether USD" }, { "asset": "MDT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Measurable Data Token/Bitcoin" }, { "asset": "MDT", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Measurable Data Token/Tron" }, { "asset": "MDT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Measurable Data Token/Tether USD" }, { "asset": "MEME", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Meme/Tether USD" }, { "asset": "MIR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Wrapped Mirror Token/Tether USD" }, { "asset": "MIST", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Alchemist/Tether USD" }, { "asset": "MKR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Maker/Bitcoin" }, { "asset": "MKR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Maker/Tether USD" }, { "asset": "MPH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "88mph/Tether USD" }, { "asset": "MTA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Meta/Tether USD" }, { "asset": "MVL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Mass Vehicle Ledger Token/Tether USD" }, { "asset": "NEO", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Neo/Bitcoin" }, { "asset": "NEO", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Neo/Tron" }, { "asset": "NEO", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Neo/Tether USD" }, { "asset": "NFT", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "APENFT/Tron" }, { "asset": "NFT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "APENFT/Tether USD" }, { "asset": "NFTX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "NFTX/Tether USD" }, { "asset": "NMR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Numeraire/Bitcoin" }, { "asset": "NU", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "NuCypher/Tether USD" }, { "asset": "NXT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "NXT/Bitcoin" }, { "asset": "OCEAN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Ocean Protocol/Tether USD" }, { "asset": "OM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "MANTRA DAO/Tether USD" }, { "asset": "OMG", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "OmiseGO/Bitcoin" }, { "asset": "ONEINCH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "1INCH Token/Tether USD" }, { "asset": "PAX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Paxos Standard/Tether USD" }, { "asset": "PBTC35A", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Poolin pBTC35A/Tether USD" }, { "asset": "PEARL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Pearl Finance/Tether USD" }, { "asset": "PERX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "PeerEx Network/Tether USD" }, { "asset": "POLS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Polkastarter/Tether USD" }, { "asset": "POLY", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Polymath/Bitcoin" }, { "asset": "PRQ", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "PARSIQ/Tether USD" }, { "asset": "QTUM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Qtum/Bitcoin" }, { "asset": "QTUM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Qtum/Tether USD" }, { "asset": "QUICK", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Quickswap/Tether USD" }, { "asset": "RARI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Rarible/Tether USD" }, { "asset": "REEF", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Reef Finance/Tether USD" }, { "asset": "REN", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Ren/Bitcoin" }, { "asset": "REN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Ren/Tether USD" }, { "asset": "REPV2", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Augur/Bitcoin" }, { "asset": "REPV2", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Augur/Tether USD" }, { "asset": "RFUEL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Rio DeFi/Tether USD" }, { "asset": "RING", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Darwinia Network Native Token/Tether USD" }, { "asset": "RLC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "RLC/Tether USD" }, { "asset": "ROOK", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "KeeperDAO/Tether USD" }, { "asset": "RSR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Reserve Rights Token/Tether USD" }, { "asset": "SAND", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "The Sandbox/Bitcoin" }, { "asset": "SAND", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "The Sandbox/Tether USD" }, { "asset": "SC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Siacoin/Bitcoin" }, { "asset": "SC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Siacoin/Tether USD" }, { "asset": "SENSO", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "SENSO/Bitcoin" }, { "asset": "SENSO", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "SENSO/Tether USD" }, { "asset": "SFI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "saffron.finance/Tether USD" }, { "asset": "SHIB", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Shiba Inu/Tether USD" }, { "asset": "SNT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Status/Bitcoin" }, { "asset": "SNX", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Synthetix Network Token/Bitcoin" }, { "asset": "SNX", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Synthetix Network Token/Tron" }, { "asset": "SNX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Synthetix Network Token/Tether USD" }, { "asset": "SRM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Serum/Tether USD" }, { "asset": "STAKE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "xDAI Stake/Tether USD" }, { "asset": "STEEM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "STEEM/Bitcoin" }, { "asset": "STEEM", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "STEEM/Tron" }, { "asset": "STEEM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "STEEM/Tether USD" }, { "asset": "STORJ", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Storj/Bitcoin" }, { "asset": "STPT", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Standard Tokenization Protocol/Bitcoin" }, { "asset": "STPT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Standard Tokenization Protocol/Tether USD" }, { "asset": "STR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Stellar/Bitcoin" }, { "asset": "STR", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Stellar/USD Coin" }, { "asset": "STR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Stellar/Tether USD" }, { "asset": "SUN", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Sun/Tron" }, { "asset": "SUN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Sun/Tether USD" }, { "asset": "SUSHI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "SushiSwap/Tether USD" }, { "asset": "SWAP", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Trustswap/Bitcoin" }, { "asset": "SWAP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Trustswap/Tether USD" }, { "asset": "SWFTC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "SwftCoin/Bitcoin" }, { "asset": "SWFTC", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "SwftCoin/Tron" }, { "asset": "SWFTC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "SwftCoin/Tether USD" }, { "asset": "SWINGBY", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Swingby/Bitcoin" }, { "asset": "SWINGBY", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Swingby/Tron" }, { "asset": "SWINGBY", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Swingby/Tether USD" }, { "asset": "SWRV", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Swerve/Tether USD" }, { "asset": "SXP", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Swipe/Bitcoin" }, { "asset": "SXP", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Swipe/Tron" }, { "asset": "SXP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Swipe/Tether USD" }, { "asset": "TAI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "tBridge Token/Tether USD" }, { "asset": "TEND", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tendies/Tether USD" }, { "asset": "TORN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tornado Cash/Tether USD" }, { "asset": "TRADE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "UniTrade/Tether USD" }, { "asset": "TRB", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tellor/Tether USD" }, { "asset": "TRU", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "TrueFi/Bitcoin" }, { "asset": "TRU", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "TrueFi/Tether USD" }, { "asset": "TRX", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tron/Bitcoin" }, { "asset": "TRX", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tron/USD Coin" }, { "asset": "TRX", "currency": "USDJ", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tron/USDJ" }, { "asset": "TRX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tron/Tether USD" }, { "asset": "TRXBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short TRX Token/Tether USD" }, { "asset": "TRXBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long TRX Token/Tether USD" }, { "asset": "TUSD", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "TrueUSD/USD Coin" }, { "asset": "TUSD", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "TrueUSD/Tether USD" }, { "asset": "UMA", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "UMA/Tether USD" }, { "asset": "UNI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Uniswap/Tether USD" }, { "asset": "USDJ", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "USDJ/Tether USD" }, { "asset": "USDT", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tether USD/USD Coin" }, { "asset": "UST", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "TerraUSD/Tether USD" }, { "asset": "VALUE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Value Liquidity/Tether USD" }, { "asset": "VSP", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Vesper Finance/Tron" }, { "asset": "VSP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Vesper Finance/Tether USD" }, { "asset": "WBTC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Wrapped Bitcoin/Bitcoin" }, { "asset": "WBTC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Wrapped Bitcoin/Tether USD" }, { "asset": "WETH", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Wrapped Ethereum on Tron/Tether USD" }, { "asset": "WHALE", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "WHALE/Tether USD" }, { "asset": "WIN", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "WINK/Tron" }, { "asset": "WIN", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "WINK/Tether USD" }, { "asset": "WNXM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Wrapped NXM/Tether USD" }, { "asset": "WRX", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "WazirX/Bitcoin" }, { "asset": "WRX", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "WazirX/Tron" }, { "asset": "WRX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "WazirX/Tether USD" }, { "asset": "XEM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "NEM/Bitcoin" }, { "asset": "XFLR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Spark [IOU]/Tether USD" }, { "asset": "XLMBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short Stellar Token/Tether USD" }, { "asset": "XLMBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long Stellar Token/Tether USD" }, { "asset": "XMR", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Monero/Bitcoin" }, { "asset": "XMR", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Monero/USD Coin" }, { "asset": "XMR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Monero/Tether USD" }, { "asset": "XOR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Sora Token/Tether USD" }, { "asset": "XRP", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "XRP/Bitcoin" }, { "asset": "XRP", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "XRP/Tron" }, { "asset": "XRP", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "XRP/USD Coin" }, { "asset": "XRP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "XRP/Tether USD" }, { "asset": "XRPBEAR", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Short XRP Token/Tether USD" }, { "asset": "XRPBULL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "3X Long XRP Token/Tether USD" }, { "asset": "XTZ", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tezos/Bitcoin" }, { "asset": "XTZ", "currency": "TRX", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Tezos/Tron" }, { "asset": "XTZ", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Tezos/Tether USD" }, { "asset": "XYM", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Symbol/Bitcoin" }, { "asset": "XYM", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Symbol/Tether USD" }, { "asset": "YFI", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "yearn.finance/Tether USD" }, { "asset": "YFII", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "DFI.money/Tether USD" }, { "asset": "YFL", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "YFLink/Tether USD" }, { "asset": "ZAP", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Zap/Tether USD" }, { "asset": "ZEC", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Zcash/Bitcoin" }, { "asset": "ZEC", "currency": "ETH", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Zcash/Ethereum" }, { "asset": "ZEC", "currency": "USDC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "Zcash/USD Coin" }, { "asset": "ZEC", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "Zcash/Tether USD" }, { "asset": "ZKS", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "ZKSwap/Tether USD" }, { "asset": "ZLOT", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "zLOT/Tether USD" }, { "asset": "ZRX", "currency": "BTC", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "0x/Bitcoin" }, { "asset": "ZRX", "currency": "ETH", "min_total": "0.0001", "max_size": null, "increment": "0.00000001", "label": "0x/Ethereum" }, { "asset": "ZRX", "currency": "USDT", "min_total": "1", "max_size": null, "increment": "0.00000001", "label": "0x/Tether USD" } ] ================================================ FILE: extensions/exchanges/poloniex/update-products.sh ================================================ #!/usr/bin/env node var request = require('micro-request') request('https://poloniex.com/public?command=returnTicker', {headers: {'User-Agent': 'zenbot/4'}}, function (err, resp, ticker) { if (err) throw err if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body console.error(err) process.exit(1) } request('https://poloniex.com/public?command=returnCurrencies', {headers: {'User-Agent': 'zenbot/4'}}, function (err, resp, currencies) { if (err) throw err if (resp.statusCode !== 200) { var err = new Error('non-200 status: ' + resp.statusCode) err.code = 'HTTP_STATUS' err.body = body console.error(err) process.exit(1) } var products = [] Object.keys(ticker).forEach(function (pair) { var asset = pair.split('_')[1], currency = pair.split('_')[0] if(currency === "USDT"){ min_total = '1' }else { min_total = '0.0001' } products.push({ asset: asset, currency: currency, min_total: min_total, max_size: null, increment: '0.00000001', label: currencies[asset].name + '/' + currencies[currency].name }) }) products.sort(function (a, b) { if (a.asset < b.asset) return -1 if (a.asset > b.asset) return 1 if (a.currency < b.currency) return -1 if (a.currency > b.currency) return 1 return 0 }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) }) ================================================ FILE: extensions/exchanges/sim/exchange.js ================================================ let path = require('path') , n = require('numbro') , _ = require('lodash') module.exports = function sim (conf, s) { let latency = 100 // In milliseconds, enough to be realistic without being disruptive let so = s.options let exchange_id = so.selector.exchange_id let real_exchange = require(path.resolve(__dirname, `../${exchange_id}/exchange`))(conf) var now var balance = { asset: so.asset_capital, currency: so.currency_capital, asset_hold: 0, currency_hold: 0 } var last_order_id = 1001 var orders = {} var openOrders = {} // When orders change in any way, it's likely our "_hold" values have changed. Recalculate them function recalcHold() { balance.currency_hold = 0 balance.asset_hold = 0 _.each(openOrders, function(order) { if (order.tradetype === 'buy') { balance.currency_hold += n(order.remaining_size).multiply(n(order.price)).value() } else { balance.asset_hold += n(order.remaining_size).value() } }) } var exchange = { name: 'sim', historyScan: real_exchange.historyScan, historyScanUsesTime: real_exchange.historyScanUsesTime, makerFee: real_exchange.makerFee, takerFee: real_exchange.takerFee, dynamicFees: real_exchange.dynamicFees, getProducts: real_exchange.getProducts, getTrades: function (opts, cb) { if (so.mode === 'paper') { return real_exchange.getTrades(opts, cb) } else { return cb(null, []) } }, getBalance: function (opts, cb) { setTimeout(function() { s.sim_asset = balance.asset return cb(null, balance) }, latency) }, getQuote: function (opts, cb) { if (so.mode === 'paper') { return real_exchange.getQuote(opts, cb) } else { setTimeout(function() { return cb(null, { bid: s.period.close, ask: s.period.close }) }, latency) } }, cancelOrder: function (opts, cb) { setTimeout(function() { var order_id = '~' + opts.order_id var order = orders[order_id] if (order.status === 'open') { order.status = 'cancelled' delete openOrders[order_id] recalcHold() } cb(null) }, latency) }, buy: function (opts, cb) { setTimeout(function() { if (so.debug) console.log(`buying ${opts.size * opts.price} vs on hold: ${balance.currency} - ${balance.currency_hold} = ${balance.currency - balance.currency_hold}`) if (opts.size * opts.price > (balance.currency - balance.currency_hold)) { if (so.debug) console.log('nope') return cb(null, { status: 'rejected', reject_reason: 'balance'}) } var result = { id: last_order_id++ } var order = { id: result.id, status: 'open', price: opts.price, size: opts.size, orig_size: opts.size, remaining_size: opts.size, post_only: !!opts.post_only, filled_size: 0, ordertype: opts.order_type, tradetype: 'buy', orig_time: now, time: now, created_at: now } orders['~' + result.id] = order openOrders['~' + result.id] = order recalcHold() cb(null, order) }, latency) }, sell: function (opts, cb) { setTimeout(function() { if (so.debug) console.log(`selling ${opts.size} vs on hold: ${balance.asset} - ${balance.asset_hold} = ${balance.asset - balance.asset_hold}`) if (opts.size > (balance.asset - balance.asset_hold)) { if (so.debug) console.log('nope') return cb(null, { status: 'rejected', reject_reason: 'balance'}) } var result = { id: last_order_id++ } var order = { id: result.id, status: 'open', price: opts.price, size: opts.size, orig_size: opts.size, remaining_size: opts.size, post_only: !!opts.post_only, filled_size: 0, ordertype: opts.order_type, tradetype: 'sell', orig_time: now, time: now, created_at: now } orders['~' + result.id] = order openOrders['~' + result.id] = order recalcHold() cb(null, order) }, latency) }, getOrder: function (opts, cb) { setTimeout(function() { var order = orders['~' + opts.order_id] cb(null, order) }, latency) }, setFees: function(opts) { if (so.mode === 'paper') { return real_exchange.setFees(opts) } }, getCursor: real_exchange.getCursor, getTime: function() { return now }, processTrade: function(trade) { var orders_changed = false now = trade.time _.each(openOrders, function(order) { if (trade.time - order.time < so.order_adjust_time) { return // Not time yet } if (order.tradetype === 'buy' && trade.price <= order.price) { processBuy(order, trade) orders_changed = true } else if (order.tradetype === 'sell' && trade.price >= order.price) { processSell(order, trade) orders_changed = true } }) if (orders_changed) recalcHold() } } function processBuy (buy_order, trade) { let fee = 0 let size = Math.min(buy_order.remaining_size, trade.size) let price = buy_order.price // Add estimated slippage to price if (so.order_type === 'maker') { price = n(price).add(n(price).multiply(so.avg_slippage_pct / 100)).format('0.00000000') } let total = n(price).multiply(size) // Compute fees if (so.order_type === 'maker' && exchange.makerFee) { fee = n(size).multiply(exchange.makerFee / 100).value() } else if (so.order_type === 'taker' && s.exchange.takerFee) { fee = n(size).multiply(exchange.takerFee / 100).value() } // Update balance balance.asset = n(balance.asset).add(size).subtract(fee).format('0.00000000') balance.currency = n(balance.currency).subtract(total).format('0.00000000') // Process existing order size changes let order = buy_order order.filled_size = order.filled_size + size order.remaining_size = order.size - order.filled_size if (order.remaining_size <= 0) { if (so.debug) console.log('full fill bought') order.status = 'done' order.done_at = trade.time delete openOrders['~' + order.id] } else { if (so.debug) console.log('partial fill buy') } } function processSell (sell_order, trade) { let fee = 0 let size = Math.min(sell_order.remaining_size, trade.size) let price = sell_order.price // Add estimated slippage to price if (so.order_type === 'maker') { price = n(price).subtract(n(price).multiply(so.avg_slippage_pct / 100)).format('0.00000000') } let total = n(price).multiply(size) // Compute fees if (so.order_type === 'maker' && exchange.makerFee) { fee = n(total).multiply(exchange.makerFee / 100).value() } else if (so.order_type === 'taker' && exchange.takerFee) { fee = n(total).multiply(exchange.takerFee / 100).value() } // Update balance balance.asset = n(balance.asset).subtract(size).value() balance.currency = n(balance.currency).add(total).subtract(fee).format('0.00000000') // Process existing order size changes let order = sell_order order.filled_size = order.filled_size + size order.remaining_size = order.size - order.filled_size if (order.remaining_size <= 0) { if (so.debug) console.log('full fill sold') order.status = 'done' order.done_at = trade.time delete openOrders['~' + order.id] } else { if (so.debug) console.log('partial fill sell') } } return exchange } ================================================ FILE: extensions/exchanges/therock/exchange.js ================================================ const ccxt = require ('ccxt'), path = require('path') module.exports = function container(conf) { var public_client, authed_client function publicClient() { if (!public_client) public_client = new ccxt.therock ({'apiKey': '', 'secret': '' }) return public_client } function authedClient() { if (!authed_client) { if (!conf.therock || !conf.therock.key || !conf.therock.key === 'YOUR-API-KEY') { throw new Error('please configure your TheRockTrading credentials in ' + path.resolve(__dirname, 'conf.js')) } authed_client = new ccxt.therock ({ 'apiKey': conf.therock.key,'secret': conf.therock.secret }) } return authed_client } function joinProduct(product_id) { return product_id.split('-')[0] + product_id.split('-')[1] } function retry(method, args) { if (method !== 'getTrades') { console.error(('\n TheRockTrading API is down! unable to call ' + method + ', retrying in 10s').red) } setTimeout(function () { exchange[method].apply(exchange, args) }, 20000) } var orders = {} var exchange = { name: 'therock', historyScan: 'forward', makerFee: 0.3, takerFee: 0.2, getProducts: function () { return require('./products.json') }, getTradesTheRock: function (args, cb, trades=[]) { let _this = this let client = publicClient() let market = client.market(args.id) try { client.request( `funds/${args.id}/trades?after=${args.after}&per_page=${args.per_page}&page=${args.page}&id=${args.id}`, 'public', 'GET', args ).then(function(response) { trades = trades.concat(response['trades']) if (response['trades'].length > 0 && response['meta'].current.page < response['meta'].next.page) { args['page'] = response['meta'].next.page return _this.getTradesTheRock(args, cb, trades) } return cb(client.parseTrades (trades, market)) }).catch(function(error) { console.log('Retrying...', error) return _this.getTradesTheRock(args, cb, trades) }) } catch(error) { console.log('Retrying...', error) return _this.getTradesTheRock(args, cb, trades) } }, getTrades: function (opts, cb) { var args = { id: joinProduct(opts.product_id), per_page: 200, page: 1 } if (opts.from) { args.after = new Date(opts.from).toISOString() } if(opts.to){ args.before = new Date(opts.to).toISOString() } this.getTradesTheRock(args, function(result) { var trades = result.map(function(trade) { return { trade_id: trade.id, time: trade.timestamp, size: parseFloat(trade.amount), price: parseFloat(trade.price), side: trade.side, } }) cb(null, trades) }) }, getBalance: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.fetchBalance().then(result =>{ var balance = {asset: 0, currency: 0} Object.keys(result).forEach(function(key){ if(key === opts.currency){ balance.currency = result[key].free balance.currency_hold = result[key].used } if(key === opts.asset){ balance.asset = result[key].free balance.asset_hold = result[key].used } cb(null, balance) }) }) .catch(function (error) { console.error('An error occurred', error) return retry('getBalance', func_args) }) }, getQuote: function (opts, cb) { var func_args = [].slice.call(arguments) var client = publicClient() client.fetchTicker({id: joinProduct(opts.product_id)}).then(result =>{ cb(null, { bid: result.bid, ask: result.ask }) }) .catch(function (error) { console.error('An error occurred', error) return retry('getQuote', func_args) }) }, cancelOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.cancelOrder(opts.order_id, function (err, resp, body) { if (body && (body.message === 'Order already done' || body.message === 'order not found')) return cb() if (err) return retry('cancelOrder', func_args) cb() }) }, buy: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { delete opts.price delete opts.post_only opts.type = 'market' } opts.side = 'buy' delete opts.order_type client.createOrder(opts.market, opts.type, opts.side, opts.amount, opts.price, opts).then(result =>{ if (result && result.message === 'Insufficient funds') { var order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } orders['~' + result.id] = result cb(null, result) }).catch(function (error) { console.error('An error occurred', error) return retry('buy', func_args) }) }, sell: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() if (typeof opts.post_only === 'undefined') { opts.post_only = true } if (opts.order_type === 'taker') { delete opts.price delete opts.post_only opts.type = 'market' } opts.side = 'sell' delete opts.order_type client.createOrder(opts.market, opts.type, opts.side, opts.amount, opts.price, opts).then(result =>{ if (result && result.message === 'Insufficient funds') { var order = { status: 'rejected', reject_reason: 'balance' } return cb(null, order) } orders['~' + result.id] = result cb(null, result) }).catch(function (error) { console.error('An error occurred', error) return retry('buy', func_args) }) }, getOrder: function (opts, cb) { var func_args = [].slice.call(arguments) var client = authedClient() client.getOrder(opts.order_id, function (err, resp, body) { if (err) return retry('getOrder', func_args) if (resp.statusCode === 404) { // order was cancelled. recall from cache body = orders['~' + opts.order_id] body.status = 'done' body.done_reason = 'canceled' } cb(null, body) }) }, getCursor: function (trade) { return (trade.time || trade) }, } return exchange } ================================================ FILE: extensions/exchanges/therock/products.json ================================================ [ { "asset": "BTC", "currency": "EUR", "increment": "0.000001", "label": "BTC/EUR" }, { "asset": "BTC", "currency": "USD", "increment": "0.000001", "label": "BTC/USD" }, { "asset": "LTC", "currency": "EUR", "increment": "0.000001", "label": "LTC/EUR" }, { "asset": "LTC", "currency": "BTC", "increment": "0.000001", "label": "LTC/BTC" }, { "asset": "BTC", "currency": "XRP", "increment": "0.000001", "label": "BTC/XRP" }, { "asset": "EUR", "currency": "XRP", "increment": "0.000001", "label": "EUR/XRP" }, { "asset": "USD", "currency": "XRP", "increment": "0.000001", "label": "USD/XRP" }, { "asset": "PPC", "currency": "EUR", "increment": "0.000001", "label": "PPC/EUR" }, { "asset": "PPC", "currency": "BTC", "increment": "0.000001", "label": "PPC/BTC" }, { "asset": "ETH", "currency": "EUR", "increment": "0.000001", "label": "ETH/EUR" }, { "asset": "ETH", "currency": "BTC", "increment": "0.000001", "label": "ETH/BTC" }, { "asset": "ZEC", "currency": "BTC", "increment": "0.000001", "label": "ZEC/BTC" }, { "asset": "ZEC", "currency": "EUR", "increment": "0.000001", "label": "ZEC/EUR" }, { "asset": "BCH", "currency": "BTC", "increment": "0.000001", "label": "BCH/BTC" } ] ================================================ FILE: extensions/exchanges/therock/update-products.sh ================================================ #!/usr/bin/env node const ccxt = require ('ccxt') const c = require('../../../conf') const therock = new ccxt.therock ({ 'apiKey': c.therock.key, 'secret': c.therock.secret, }) therock.fetch_markets('BTCUSD') .then(result => { var products = [] result.forEach(function (product) { console.log(product) products.push({ asset: product.base, currency: product.quote, increment: '0.000001', label: product.symbol }) }) var target = require('path').resolve(__dirname, 'products.json') require('fs').writeFileSync(target, JSON.stringify(products, null, 2)) console.log('wrote', target) process.exit() }) .catch(function (error) { console.error('An error occurred', error) process.exit(1) }) ================================================ FILE: extensions/notifiers/adamant.js ================================================ module.exports = function adamant (config) { const api = require('adamant-api')({passPhrase: config.fromPassphrase, node: config.nodes, logLevel: 'error'}, null) var adamant = { pushMessage: function(title, message) { config.toAddresses.forEach(address => { if (address) var result = api.send(config.fromPassphrase, address, title + ': ' + message, 'message') if (!result.success) { console.error(`Message to address ${address} was not accepted by ADAMANT node: ${result.error}.`) } }) } } return adamant } ================================================ FILE: extensions/notifiers/discord.js ================================================ var request = require('request') module.exports = function discord (config) { var discord = { pushMessage: function(title, message) { var postData = { 'username': (config.username != '' ? config.username : 'Zenbot'), 'avatar_url': (config.avatar_url != '' ? config.avatar_url : 'https://camo.githubusercontent.com/db46d81f1352cee31f9baea72dc4396a15ad1d3e/68747470733a2f2f7261776769742e636f6d2f6361726c6f7338662f7a656e626f742f6d61737465722f6173736574732f7a656e626f745f7371756172652e706e67'), 'embeds': [{ 'color': (config.color != null ? config.color : 15258703), 'fields': [{ 'name': title, 'value': message }] }] } function callback(error) { if (error) { console.log('Error happened: '+ error) } } var options = { method: 'POST', url: 'https://discordapp.com/api/webhooks/' + config.id + '/' + config.token, json: postData } request(options, callback) } } return discord } ================================================ FILE: extensions/notifiers/ifttt.js ================================================ var request = require('request') module.exports = function ifttt (config) { var ifttt = { pushMessage: function(title, message) { var postData = {'value1': title , 'value2': message } function callback(error) { if (error) { console.log('Error happened: '+ error) } } var options = { method: 'POST', url: 'https://maker.ifttt.com/trigger/' + config.eventName + '/with/key/' + config.makerKey, json: postData } request(options, callback) } } return ifttt } ================================================ FILE: extensions/notifiers/prowl.js ================================================ var Prowl = require('node-prowl') module.exports = function prowl (config) { var prowl = { pushMessage: function(title, message) { var p = new Prowl(config.key) p.push(message, title, function(err) { if (err) { console.log('error: Push message failed, ' + err) return } }) } } return prowl } ================================================ FILE: extensions/notifiers/pushbullet.js ================================================ var pusher = require('pushbullet') module.exports = function pushbullet (config) { var pushbullet = { pushMessage: function(title, message) { var pb = new pusher(config.key) pb.note(config.deviceID, title, message, (err) => { if (err) { console.log('error: Push message failed, ' + err) return } }) } } return pushbullet } ================================================ FILE: extensions/notifiers/pushover.js ================================================ var request = require('request') module.exports = function pushover (config) { var pushover = { pushMessage: function(title, message) { var postData = { 'token': config.token, 'user': config.user, 'tite': title, 'message': message, 'priority': config.priority } function callback(error) { if (error) { console.log('Error happened: '+ error) } } var options = { method: 'POST', url: 'https://api.pushover.net/1/messages.json', json: postData } request(options, callback) } } return pushover } ================================================ FILE: extensions/notifiers/slack.js ================================================ var IncomingWebhook = require('@slack/client').IncomingWebhook module.exports = function slack (config) { var slack = { pushMessage: function(title, message) { var slackWebhook = new IncomingWebhook(config.webhook_url || '', {}) slackWebhook.send(title + ': ' + message, function (err) { if (err) { console.error('\nerror: slack webhook') console.error(err) } }) } } return slack } ================================================ FILE: extensions/notifiers/telegram.js ================================================ process.env['NTBA_FIX_319'] = 1 var TelegramBot = require('node-telegram-bot-api') module.exports = function telegram (config) { var bot = new TelegramBot(config.bot_token, { polling: true }) var wrapper = function(cb) { return function(message) { if (message.chat.id != config.chat_id) { console.log('\nChat ID error: command coming from wrong chat: ' + message.chat.id) return } cb(message.text) } } var telegram = { pushMessage: function(title, message) { bot.sendMessage(config.chat_id, title + ': ' + message).catch(function (error) { console.error('\nerror: telegram notification') console.log(error.response.body) // => { ok: false, error_code: 400, description: 'Bad Request: chat not found' } }) }, onMessage: function (callback) { bot.on('message', wrapper(callback)) bot.on('webhook_error', (error) => { console.log('\nwebhook error: telegram event ' + error.code) }) bot.on('polling_error', (error) => { console.log('\npolling error: telegram event ' + error.code) }) bot.on('error', (error) => { console.log('\nerror: telegram event ' + error.code) }) } } return telegram } ================================================ FILE: extensions/notifiers/textbelt.js ================================================ var request = require('request') module.exports = function textbelt (config) { var textbelt = { pushMessage: function(title, message) { var postData = {'number': config.phone, 'message': title+': '+message, 'key': config.key } function callback(error) { if (error) { console.log('Error happened: '+ error) } } var options = { method: 'POST', url: 'https://textbelt.com/text', json: postData } request(options, callback) } } return textbelt } ================================================ FILE: extensions/notifiers/xmpp.js ================================================ var simplexmpp = require('simple-xmpp') module.exports = function xmpp (config) { var xmpp = { pushMessage: function(title, message) { if (!simplexmpp.conn) { simplexmpp.connect({ jid : config.jid, password : config.password, host : config.host, port : config.port, reconnect : true }) } simplexmpp.send(config.to, title + ': ' + message) } } return xmpp } ================================================ FILE: extensions/output/_codemap.js ================================================ module.exports = { _ns: 'zenbot', 'output.api': require('./api') } ================================================ FILE: extensions/output/api.js ================================================ module.exports = function api () { let express = require('express') let app = express() let random_port = require('random-port') let path = require('path') let moment = require('moment') let run = function(reporter, tradeObject) { if (!reporter.port || reporter.port === 0) { random_port({from: 20000}, function(port) { startServer(port, reporter.ip, tradeObject) }) } else { startServer(reporter.port, reporter.ip, tradeObject) } } let objectWithoutKey = (object, key) => { // eslint-disable-next-line no-unused-vars const {[key]: deletedKey, ...otherKeys} = object return otherKeys } // set up rate limiter: maximum of fifty requests per minute let RateLimit = require('express-rate-limit'); let limiter = new RateLimit({ windowMs: 1*60*1000, // 1 minute max: 50 }); let startServer = function(port, ip, tradeObject) { tradeObject.port = port app.set('views', path.join(__dirname+'/../../templates')) app.set('view engine', 'ejs') app.use(limiter); app.use('/assets', express.static(__dirname+'/../../templates/dashboard_assets')) app.use('/assets-wp', express.static(__dirname+'/../../dist/')) app.use('/assets-zenbot', express.static(__dirname+'/../../assets')) app.get('/', function (req, res) { app.locals.moment = moment app.locals.deposit = tradeObject.options.deposit let datas = JSON.parse(JSON.stringify(objectWithoutKey(tradeObject, 'options'))) // deep copy to prevent alteration res.render('dashboard', datas) }) app.get('/trades', function (req, res) { res.send(objectWithoutKey(tradeObject, 'options')) }) app.get('/stats', function (req, res) { res.sendFile(path.join(__dirname+'../../../stats/index.html')) }) if (ip && ip !== '0.0.0.0') { app.listen(port, ip) tradeObject.url = ip + ':' + port + '/' } else { app.listen(port) tradeObject.url = require('ip').address() + ':' + port + '/' } console.log('Web GUI running on http://' + tradeObject.url) } return { run: run } } ================================================ FILE: extensions/strategies/bollinger/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , bollinger = require('../../../lib/bollinger') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'bollinger', description: 'Buy when (Signal ≤ Lower Bollinger Band) and sell when (Signal ≥ Upper Bollinger Band).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('bollinger_size', 'period size', Number, 20) this.option('bollinger_time', 'times of standard deviation between the upper band and the moving averages', Number, 2) this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 0) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) }, calculate: function (s) { // calculate Bollinger Bands bollinger(s, 'bollinger', s.options.bollinger_size) }, onPeriod: function (s, cb) { if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { s.signal = 'sell' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { s.signal = 'buy' } else { s.signal = null // hold } } } cb() }, onReport: function (s) { var cols = [] if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound var color = 'grey' if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { color = 'green' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy bollinger_size: Phenotypes.Range(1, 40), bollinger_time: Phenotypes.RangeFloat(1,6), bollinger_upper_bound_pct: Phenotypes.RangeFloat(-1, 30), bollinger_lower_bound_pct: Phenotypes.RangeFloat(-1, 30) } } ================================================ FILE: extensions/strategies/cci_srsi/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , ema = require('../../../lib/ema') , srsi = require('../../../lib/srsi') , cci = require('../../../lib/cci') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'cci_srsi', description: 'Stochastic CCI Strategy', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '20m') this.option('period_length', 'period length, same as --period', String, '20m') this.option('min_periods', 'min. number of history periods', Number, 30) this.option('ema_acc', 'sideways threshold (0.2-0.4)', Number, 0.03) this.option('cci_periods', 'number of CCI periods', Number, 14) this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('srsi_periods', 'number of SRSI periods', Number, 9) this.option('srsi_k', '%K line', Number, 5) this.option('srsi_d', '%D line', Number, 3) this.option('oversold_rsi', 'buy when RSI reaches or drops below this value', Number, 18) this.option('overbought_rsi', 'sell when RSI reaches or goes above this value', Number, 85) this.option('oversold_cci', 'buy when CCI reaches or drops below this value', Number, -90) this.option('overbought_cci', 'sell when CCI reaches or goes above this value', Number, 140) this.option('constant', 'constant', Number, 0.015) console.log('If you have questions about this strategy, contact me... @talvasconcelos') }, calculate: function (s) { //get market trend ema(s, 'trend_ema', s.options.min_periods) if (typeof s.period.trend_ema !== 'undefined') s.trend = s.period.trend_ema > s.lookback[0].trend_ema ? 'up' : 'down' // compute Stochastic RSI srsi(s, 'srsi', s.options.rsi_periods, s.options.srsi_k, s.options.srsi_d) // compute CCI cci(s, 'cci', s.options.cci_periods, s.options.constant) if (typeof s.period.cci !== 'undefined' && typeof s.period.srsi_K !== 'undefined') { s.cci_fromAbove = s.period.cci < s.lookback[0]['cci'] s.rsi_fromAbove = s.period.srsi_K < s.lookback[0]['srsi_K'] } if (s.period.trend_ema && s.lookback[0] && s.lookback[0].trend_ema) { s.period.acc = Math.abs((s.period.trend_ema - s.lookback[0].trend_ema) / s.lookback[0].trend_ema * 100) } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.trend !== 'undefined') { // Sideways Market if (s.period.acc < s.options.ema_acc) { // Buy signal if (s.period.cci <= s.options.oversold_cci && /*s.period.srsi_K > s.period.srsi_D &&*/ s.period.srsi_K <= s.options.oversold_rsi) { if (!s.cci_fromAbove && !s.rsi_fromAbove) { s.signal = 'buy' } } // Sell signal if (s.period.cci >= s.options.overbought_cci && /*s.period.srsi_K < s.period.srsi_D &&*/ s.period.srsi_K >= s.options.overbought_rsi) { if (s.cci_fromAbove || s.rsi_fromAbove) { s.signal = 'sell' } } //cb() } // Buy signal if (s.trend === 'up') { if (s.period.cci <= s.options.oversold_cci && /*s.period.srsi_K > s.period.srsi_D &&*/ s.period.srsi_K <= s.options.oversold_rsi) { if (!s.cci_fromAbove && !s.rsi_fromAbove) { s.signal = 'buy' } } } // Sell signal if (s.trend === 'down') { if (s.period.cci >= s.options.overbought_cci && /*s.period.srsi_K < s.period.srsi_D &&*/ s.period.srsi_K >= s.options.overbought_rsi) { if (s.cci_fromAbove || s.rsi_fromAbove) { s.signal = 'sell' } } } } cb() }, onReport: function (s) { var cols = [] if (typeof s.period.cci === 'number') { var color = 'grey' if (s.period.cci > 0) { color = 'green' } else if (s.period.cci < 0) { color = 'red' } cols.push(z(8, n(s.period.cci).format('000'), ' ')[color]) cols.push(s.period.acc > s.options.ema_acc ? z(8, n(s.period.srsi_K).format('000'), ' ')[color] : ' --> ') } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy ema_acc: Phenotypes.RangeFloat(0, 0.5), cci_periods: Phenotypes.Range(1, 200), rsi_periods: Phenotypes.Range(1, 200), srsi_periods: Phenotypes.Range(1, 200), srsi_k: Phenotypes.Range(1, 50), srsi_d: Phenotypes.Range(1, 50), oversold_rsi: Phenotypes.Range(1, 100), overbought_rsi: Phenotypes.Range(1, 100), oversold_cci: Phenotypes.Range(-100, 100), overbought_cci: Phenotypes.Range(1, 100), constant: Phenotypes.RangeFloat(0.001, 0.05) } } /* Made by talvasconcelos*/ ================================================ FILE: extensions/strategies/crossover_vwap/example_sims/index.html ================================================

VWAP Max (--vwap_max)

================================================ FILE: extensions/strategies/crossover_vwap/example_sims/main.css ================================================ html { height: 100%; } body { font: 10px sans-serif; background-color: #000000; color: #fff; position: relative; } svg { margin: 50px 0 0 0; width: 100%; height: auto; z-index: 2; } .axis path, .axis line { fill: none; stroke: #444; shape-rendering: crispEdges; } .axis.x path { stroke: none; } text { fill: #fff; } text.symbol { fill: #BBBBBB; } path { fill: none; stroke-width: 1; } path.candle { stroke: #888; } path.candle.up { stroke: rgb(85, 255, 14); } path.candle.down { fill: rgb(232, 87, 35); stroke: #944329; } .close.annotation.up path { stroke: #8ff; stroke-width: 1; fill: #8ff; } .close.annotation.up text { fill: #000; } path.volume { fill: #588bbd; } .indicator-plot path.line { fill: none; stroke-width: 1; } .ma-0 path.line { stroke: #1f77b4; stroke-width: 2; } .ma-1 path.line { stroke: #aec7e8; stroke-width: 2; } .ma-2 path.line { stroke: #00ff65; stroke-width: 2; } .sma-0 path.line { stroke: #ff0d6d; stroke-width: 2; } .sma-1 path.line { stroke: #910eff; stroke-width: 2; } .indicator4 path.line { stroke: gold; stroke-width: 3; } path.adx{ stroke: #ff7f0e; } button { position: absolute; right: 110px; top: 25px; } path.macd { stroke: #a0f; } path.signal { stroke: #0f0; } path.difference { fill: #35474c; } path.rsi { stroke: #09d; } path.overbought { stroke: #9f9; stroke-dasharray: 1, 5; } path.oversold { stroke: #f99; stroke-dasharray: 1, 5; } path.middle, path.zero { stroke: #888; stroke-opacity: 0.5; stroke-dasharray: 1, 5; } .analysis path, .analysis circle { stroke: blue; stroke-width: 0.8; } .trendline circle { stroke-width: 0; display: none; } .mouseover .trendline path { stroke-width: 1.2; } .mouseover .trendline circle { stroke-width: 1; display: inline; } .dragging .trendline path, .dragging .trendline circle { stroke: darkblue; } .interaction path, .interaction circle { pointer-events: all; } .interaction .body { cursor: move; } .trendlines .interaction .start, .trendlines .interaction .end { cursor: nwse-resize; } .supstance path { stroke-dasharray: 2, 2; } .supstances .interaction path { pointer-events: all; cursor: ns-resize; } .mouseover .supstance path { stroke-width: 1.5; } .dragging .supstance path { stroke: darkblue; } .crosshair { cursor: crosshair; } .crosshair path.wire { stroke: #fff; stroke-opacity: 0.5; stroke-dasharray: 1, 5; } .crosshair .axisannotation path { fill: #000; stroke: #fff; } .axisannotation.y path { stroke: #fff; } .tradearrow path.tradearrow { stroke: none; } .tradearrow path.buy { fill: #00ff87; } .tradearrow path.sell { fill: #ff0000; } .tradearrow path.highlight { fill: none; stroke-width: 2; } .tradearrow path.highlight.buy { stroke: #0000FF; } .tradearrow path.highlight.sell { stroke: #9900FF; } .loading { width: 50%; height: 50%; overflow: auto; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; text-align: center; font-size: 80px; z-index: 1; color: #888; } .no-data { display: none; color: #888; font-size: 80px; text-align: center; } .options { position: absolute; top: 20px; left: 20px; z-index: 3; } .footer { position: fixed; right: 20px; bottom: 20px; color: #aac; font-size: 1.2em; } .footer a { color: cyan; text-decoration: none; } pre { font-size: 2em; } ================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax0.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax0.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 0
}
end balance: 1006.01715054 (43.72%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: -20.27%
5 trades over 62 days (avg 0.08 trades/day)
win/loss: 3/0
error rate: 0.00%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax10.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax10.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 10
}
end balance: 1525.92919381 (117.99%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 20.93%
51 trades over 62 days (avg 0.82 trades/day)
win/loss: 20/6
error rate: 23.08%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax100.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax100.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 100
}
end balance: 1331.33355047 (90.19%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 5.51%
56 trades over 62 days (avg 0.90 trades/day)
win/loss: 19/9
error rate: 32.14%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax1000.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax1000.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 1000
}
end balance: 1602.20161795 (128.89%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 26.98%
36 trades over 62 days (avg 0.58 trades/day)
win/loss: 12/6
error rate: 33.33%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax10000.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax10000.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 10000
}
end balance: 1469.07665511 (109.87%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 16.43%
19 trades over 62 days (avg 0.31 trades/day)
win/loss: 3/6
error rate: 66.67%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax20000.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax20000.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 20000
}
end balance: 1164.18233610 (66.31%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: -7.74%
20 trades over 62 days (avg 0.32 trades/day)
win/loss: 2/7
error rate: 77.78%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax500.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax500.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 500
}
end balance: 1285.43743401 (83.63%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 1.87%
45 trades over 62 days (avg 0.73 trades/day)
win/loss: 16/7
error rate: 30.43%
================================================ FILE: extensions/strategies/crossover_vwap/example_sims/vwapmax5000.html ================================================ kraken.XXRP-ZEUR - zenbot 4.0.5 sim result
{
  "asset_capital": 0,
  "avg_slippage_pct": 0.045,
  "buy_pct": 99,
  "buy_stop_pct": 0,
  "currency_capital": 700,
  "days": 60,
  "emalen1": 30,
  "filename": "simulations/vwapmax5000.html",
  "markdown_buy_pct": 0.5,
  "markup_sell_pct": 0.5,
  "max_sell_loss_pct": 25,
  "max_slippage_pct": "100",
  "min_periods": 1,
  "mode": "sim",
  "order_adjust_time": 5000,
  "order_type": "maker",
  "period": "120m",
  "profit_stop_enable_pct": 0,
  "profit_stop_pct": 1,
  "rsi_periods": 14,
  "selector": "kraken.XXRP-ZEUR",
  "sell_pct": 99,
  "sell_stop_pct": 0,
  "show_options": true,
  "smalen1": 108,
  "smalen2": 60,
  "start": 1507939200000,
  "stats": false,
  "strategy": "crossover_vwap",
  "verbose": false,
  "vwap_length": 10,
  "vwap_max": 5000
}
end balance: 1539.27499850 (119.90%)
buy hold: 1261.79569400 (80.26%)
vs. buy hold: 21.99%
22 trades over 62 days (avg 0.35 trades/day)
win/loss: 7/4
error rate: 36.36%
================================================ FILE: extensions/strategies/crossover_vwap/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , vwap = require('../../../lib/vwap') , ema = require('../../../lib/ema') , sma = require('../../../lib/sma') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'crossover_vwap', description: 'Estimate trends by comparing "Volume Weighted Average Price" to the "Exponential Moving Average".', getOptions: function () { // default start is 30, 108, 60. // these are relative to period length. /* Positive simulations during testing: zenbot sim kraken.XXRP-ZEUR --period="120m" --strategy=crossover_vwap --currency_capital=700 --asset_capital=0 --max_slippage_pct=100 --days=60 --avg_slippage_pct=0.045 --vwap_max=8000 --markup_sell_pct=0.5 --markdown_buy_pct=0.5 --emalen1=50 zenbot sim kraken.XXRP-ZEUR --period="120m" --strategy=crossover_vwap --currency_capital=700 --asset_capital=0 --max_slippage_pct=100 --days=60 --avg_slippage_pct=0.045 --vwap_max=8000 --markup_sell_pct=0.5 --markdown_buy_pct=0.5 --emalen1=30 */ this.option('period', 'period length, same as --period_length', String, '120m') this.option('period_length', 'period length, same as --period', String, '120m') this.option('emalen1', 'Length of EMA 1', Number, 30 )//green this.option('smalen1', 'Length of SMA 1', Number, 108 )//red this.option('smalen2', 'Length of SMA 2', Number, 60 )//purple this.option('vwap_length', 'Min periods for vwap to start', Number, 10 )//gold this.option('vwap_max', 'Max history for vwap. Increasing this makes it more sensitive to short-term changes', Number, 8000)//gold }, calculate: function () { }, onPeriod: function (s, cb) { vwap(s, 'vwap', s.options.vwap_length, s.options.vwap_max)//gold ema(s, 'ema1', s.options.emalen1)//green sma(s, 'sma1', s.options.smalen1, 'high')//red sma(s, 'sma2', s.options.smalen2)//purple let emagreen = s.period.ema1, smared = s.period.sma1, smapurple= s.period.sma2, vwapgold = s.period.vwap // helper functions var trendUp = function(s){ if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null }, trendDown = function(s){ if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } if(emagreen && smared && smapurple && s.period.vwap){ if(vwapgold > emagreen) trendUp(s) else trendDown(s) } cb() }, onReport: function (s) { var cols = [] let emagreen = s.period.ema1, vwapgold = s.period.vwap if (vwapgold && emagreen) { var color = 'green' if(vwapgold > emagreen) color = 'red' cols.push(z(6, n(vwapgold).format('0.00000'), '')['yellow'] + ' ') cols.push(z(6, n(emagreen).format('0.00000'), '')[color] + ' ') } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 400, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy emalen1: Phenotypes.Range(1, 300), smalen1: Phenotypes.Range(1, 300), smalen2: Phenotypes.Range(1, 300), vwap_length: Phenotypes.Range(1, 300), vwap_max: Phenotypes.RangeFactor(0, 10000, 10)//0 disables this max cap. Test in increments of 10 } } ================================================ FILE: extensions/strategies/dema/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'dema', description: 'Buy when (short ema > long ema) and sell when (short ema < long ema).', getOptions: function () { this.option('period', 'period length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 21) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 10) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 21) this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 9) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 80) this.option('noise_level_pct', 'do not trade when short ema is with this % of last short ema', Number, 0) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } // compture DEMA ema(s, 'ema_short', s.options.ema_short_period) ema(s, 'ema_long', s.options.ema_long_period) if (s.period.ema_short && s.period.ema_long) { s.period.dema_histogram = (s.period.ema_short - s.period.ema_long) } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.trend = 'overbought' s.signal = 'sold' return cb() } } if (typeof s.period.dema_histogram === 'number' && typeof s.lookback[0].dema_histogram === 'number') { if (s.options.noise_level_pct != 0 && (s.period.ema_short / s.lookback[0].ema_short * 100 < s.options.noise_level_pct)) { s.signal = null } else if ((s.period.dema_histogram - s.options.up_trend_threshold) > 0 && (s.lookback[0].dema_histogram - s.options.up_trend_threshold) <= 0) { s.signal = 'buy' } else if ((s.period.dema_histogram + s.options.down_trend_threshold) < 0 && (s.lookback[0].dema_histogram + s.options.down_trend_threshold) >= 0) { s.signal = 'sell' } else { s.signal = null // hold } } cb() }, onReport: function (s) { var cols = [] if (typeof s.period.dema_histogram === 'number') { var color = 'grey' if (s.period.dema_histogram > 0) { color = 'green' } else if (s.period.dema_histogram < 0) { color = 'red' } cols.push(z(8, n(s.period.dema_histogram).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.overbought_rsi).format('00'), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy ema_short_period: Phenotypes.Range(1, 20), ema_long_period: Phenotypes.Range(20, 100), up_trend_threshold: Phenotypes.Range(0, 50), down_trend_threshold: Phenotypes.Range(0, 50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ehlers_ft/strategy.js ================================================ /* Author: Travis Adapted from: https://www.tradingview.com/script/Q0eQz7ll-Fisher-Transform-Indicator-by-Ehlers-Strategy/ Description: Market prices do not have a Gaussian probability density function as many traders think. Their probability curve is not bell-shaped. But trader can create a nearly Gaussian PDF for prices by normalizing them or creating a normalized indicator such as the relative strength index and applying the Fisher transform . Such a transformed output creates the peak swings as relatively rare events. Fisher transform formula is: y = 0.5 * ln ((1+x)/(1-x)) The sharp turning points of these peak swings clearly and unambiguously identify price reversals in a timely manner. Author Notes: pos = 1 indicates the fisher transform value for the period was ABOVE the previous period pos = -1 indicates the fisher transform value for the period was BELOW the previous period pos_length = 1 does default behavior from the original tradingview strategy. If pos_length > 1, make sure pos_length number of previous periods have opposite pos values. Sample sim command: zenbot sim gdax.LTC-USD --strategy ehlers_ft --period_length 15m --days 3 --order_type maker --fish_pct_change 0 --length 10 --pos_length 1 --src HAohlc4 --min_periods 20 If you have found this strategy useful and would like to show your appreciation, please consider donating ETH, BTC, or LTC to the developer, Travis. ETH: 0xdA963A127BeCB08227583d11f912F400D5347060 BTC: 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW LTC: MSePEwGJF8W4wvGCbJBqMtatwdBGYhT8FM Please direct feedback concerning this strategy to the zenbot strategies discord channel @Travis: https://discordapp.com/channels/316120967200112642/383023593942155274 */ const z = require('zero-fill'), n = require('numbro'), Phenotypes = require('../../../lib/phenotype'), tv = require('../../../lib/helpers') module.exports = { name: 'ehlers_fisher_transform', description: '', getOptions: function() { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') this.option('fish_pct_change', 'percent change of fisher transform for reversal', Number, 0) this.option('length', 'number of past periods to use including current', Number, 10) this.option('src', 'use period.close if not defined. can be hl2, hlc3, ohlc4, HAhlc3, HAohlc4', String, 'hl2') this.option('pos_length', 'check this number of previous periods have opposing pos value', Number, 1) }, calculate: function() {}, onPeriod: function(s, cb) { // console.log('') if (!s.eft) { s.eft = { n1: [], fish: [], pos: [], } s.eft_max_elements = Math.max(s.options.pos_length, 3) } s.period.src = tv.src(s.options.src, s.period, s.lookback[0]) let lbks = s.lookback.slice(0, s.options.length - 1).map(p => p.src), maxH = Math.max(s.period.src, ...lbks), minL = Math.min(s.period.src, ...lbks) s.eft.n1.unshift(0.33 * 2 * ((s.period.src - minL) / (maxH - minL) - 0.5) + 0.67 * tv.nz(s.eft.n1[0])) let n2 = tv.iff(s.eft.n1[0] > 0.99, 0.999, tv.iff(s.eft.n1[0] < -0.99, -0.999, s.eft.n1[0])) s.eft.fish.unshift(0.5 * Math.log((1 + n2) / (1 - n2)) + 0.5 * tv.nz(s.eft.fish[0])) s.eft.pos.unshift( tv.iff(s.eft.fish[0] > tv.nz(s.eft.fish[1] * (1 + s.options.fish_pct_change / 100)), 1, tv.iff(s.eft.fish[0] < tv.nz(s.eft.fish[1] * (1 - s.options.fish_pct_change / 100)), -1, tv.nz(s.eft.pos[0], 0)))) if (!s.in_preroll) { if (s.options.pos_length === 1) { if (s.eft.pos[0] === 1) { s.signal = 'buy' } else if (s.eft.pos[0] === -1) { s.signal = 'sell' } else { s.signal = null } } else { let pos = s.eft.pos.slice(1, s.options.pos_length + 1), posUp = s.eft.pos[0] === -1 && pos.every(pos => pos === 1), posDn = s.eft.pos[0] === 1 && pos.every(pos => pos === -1) if (posUp) { s.signal = 'buy' } else if (posDn) { s.signal = 'sell' } else s.signal = null } } // cleanup if (s.eft.pos.length > s.eft_max_elements) Object.keys(s.eft).forEach(k => { s.eft[k].pop() }) cb() }, onReport: function(s) { var cols = [] cols.push(z(10, 'F[' + n(s.eft.fish[0]).format('#.000') + ']', '')) cols.push(z(10, ' P[' + n(s.eft.pos[0]).format('##') + ']', '')) return cols }, phenotypes: { //General Options period_length: Phenotypes.RangePeriod(5, 300, 'm'), min_periods: Phenotypes.Range(10, 40), markdown_buy_pct: Phenotypes.RangeFloat(0, 10), markup_sell_pct: Phenotypes.RangeFloat(0, 10), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range(1, 20), profit_stop_pct: Phenotypes.Range(1, 10), //Strategy Specific length: Phenotypes.Range(1, 30), fish_pct_change: Phenotypes.Range(-25, 75), pos_length: Phenotypes.Range(1, 6), src: Phenotypes.ListOption(['close', 'hl2', 'hlc3', 'ohlc4', 'HAhlc3', 'HAohlc4']) } } /* // Original pinescript // From https://www.tradingview.com/script/Q0eQz7ll-Fisher-Transform-Indicator-by-Ehlers-Strategy/ study(title="Fisher Transform Indicator by Ehlers Strategy", shorttitle="Fisher Transform Indicator by Ehlers") Length = input(10, minval=1) xHL2 = hl2 xMaxH = highest(xHL2, Length) xMinL = lowest(xHL2,Length) nValue1 = 0.33 * 2 * ((xHL2 - xMinL) / (xMaxH - xMinL) - 0.5) + 0.67 * nz(nValue1[1]) nValue2 = iff(nValue1 > .99, .999, iff(nValue1 < -.99, -.999, nValue1)) nFish = 0.5 * log((1 + nValue2) / (1 - nValue2)) + 0.5 * nz(nFish[1]) pos = iff(nFish > nz(nFish[1]), 1, iff(nFish < nz(nFish[1]), -1, nz(pos[1], 0))) barcolor(pos == -1 ? red: pos == 1 ? green : blue ) plot(nFish, color=green, title="Fisher") plot(nz(nFish[1]), color=red, title="Trigger") */ ================================================ FILE: extensions/strategies/ehlers_mama/README.md ================================================ ======= Ehlers MESA Adaptive Moving Average ======= Developed by John Ehlers, the MESA Adaptive Moving Average is a technical trend-following indicator which, according to its creator, adapts to price movement “based on the rate change of phase as measured by the Hilbert Transform Discriminator”. This method of adaptation features a fast and a slow moving average so that the composite moving average swiftly responds to price changes and holds the average value until the next bar’s close. Ehlers states that because the average’s fallback is slow, you can create trading systems with almost whipsaw-free trades. Basically the indicator looks like two moving averages, but instead of curving around the price action, the MESA Adaptive MA moves in a staircase manner as the price ratchets. It produces two outputs, MAMA and FAMA. FAMA (Following Adaptive Moving Average) is a result of MAMA being applied to the first MAMA line. The FAMA is synchronized in time with MAMA, but its vertical movement comes with a lag. Thus, the two don’t cross unless a major change in market direction occurs, resulting in a moving average crossover system which is “virtually free of whipsaw trades”, according to Ehlers. If you appreciate the work and the man hours that went into creating this strategy, please consider giving back. LoneWolf345 ETH = 0xa42f6d21f1e52f7fbaeaa0f58d1cc4b9a58f2dcc , BTC = 15L8QstCQG4ho6139hVaqLxkAzcjnqBbf6 Travis ETH = 0xdA963A127BeCB08227583d11f912F400D5347060 , BTC = 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW ===== Trading View Script ===== //@version=2 strategy("Ehlers MESA Adaptive Moving Average", shorttitle="Ehlers_MAMA", overlay=true, precision=3, initial_capital=1000) // === INPUTS src=input(hlc3, title="Source") fl=input(.5, title="Fast Limit", step=0.5) sl=input(.05, title="Slow Limit", step=0.05) pa=input(true, title="Mark crossover points") fr=input(true, title="Fill MAMA/FAMA Region") ebc=input(false, title="Enable Bar colors") // === /INPUTS // === FUNCTIONS pi = 3.1415926 sp = (4*src + 3*src[1] + 2*src[2] + src[3]) / 10.0 dt = (.0962*sp + .5769*nz(sp[2]) - .5769*nz(sp[4])- .0962*nz(sp[6]))*(.075*nz(p[1]) + .54) q1 = (.0962*dt + .5769*nz(dt[2]) - .5769*nz(dt[4])- .0962*nz(dt[6]))*(.075*nz(p[1]) + .54) i1 = nz(dt[3]) jI = (.0962*i1 + .5769*nz(i1[2]) - .5769*nz(i1[4])- .0962*nz(i1[6]))*(.075*nz(p[1]) + .54) jq = (.0962*q1 + .5769*nz(q1[2]) - .5769*nz(q1[4])- .0962*nz(q1[6]))*(.075*nz(p[1]) + .54) i2_ = i1 - jq q2_ = q1 + jI i2 = .2*i2_ + .8*nz(i2[1]) q2 = .2*q2_ + .8*nz(q2[1]) re_ = i2*nz(i2[1]) + q2*nz(q2[1]) im_ = i2*nz(q2[1]) - q2*nz(i2[1]) re = .2*re_ + .8*nz(re[1]) im = .2*im_ + .8*nz(im[1]) p1 = iff(im!=0 and re!=0, 360/atan(im/re), nz(p[1])) p2 = iff(p1 > 1.5*nz(p1[1]), 1.5*nz(p1[1]), iff(p1 < 0.67*nz(p1[1]), 0.67*nz(p1[1]), p1)) p3 = iff(p2<6, 6, iff (p2 > 50, 50, p2)) p = .2*p3 + .8*nz(p3[1]) spp = .33*p + .67*nz(spp[1]) phase = atan(q1 / i1) dphase_ = nz(phase[1]) - phase dphase = iff(dphase_< 1, 1, dphase_) alpha_ = fl / dphase alpha = iff(alpha_ < sl, sl, iff(alpha_ > fl, fl, alpha_)) mama = alpha*src + (1 - alpha)*nz(mama[1]) fama = .5*alpha*mama + (1 - .5*alpha)*nz(fama[1]) plotarrow(pa?(cross(mama, fama)?mamafama?mama:fama):na, style=circles, color=gray, linewidth=0, title="DummyL") mamal=plot(mama, title="MAMA", color=red, linewidth=0) famal=plot(fama, title="FAMA", color=green, linewidth=0) fill(duml, mamal, red, transp=50, title="NegativeFill") fill(duml, famal, green, transp=50, title="PositiveFill") bc=mama>fama?lime:red // === Upgraded Conditions Framework === //////////////////////////////////////////////////////////////////////////// long_entry = cross(mama, fama)?mama>fama?true:false:false short_entry = cross(mama, fama)?mama last_shortCondition and last_longCondition >= last_longClose in_shortCondition = last_shortCondition > last_longCondition and last_shortCondition >= last_shortClose // === /END // === Stop Loss (Long) === isSLl = input(false, "Stop Loss (Long)") sll = input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 long_call_sl = last_open_longCondition * (1 - sll) long_sl = isSLl and low <= long_call_sl and longCondition == 0 // === /END // === Stop Loss (Short) === isSLs = false //input(false, "Stop Loss (Short)") sls = 6 //input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 short_call_sl = last_open_shortCondition * (1 + sls) short_sl = isSLs and high >= short_call_sl and shortCondition == 0 // === /END // === Trailing Stop === last_high = na last_low = na last_high := in_longCondition ? (na(last_high[1]) or high > nz(last_high[1])) ? high : nz(last_high[1]) : na last_low := in_shortCondition ? (na(last_low[1]) or low < nz(last_low[1])) ? low : nz(last_low[1]) : na isTSl = input(false, "Trailing Stop Long") tsil = input(25, "Activate Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 tsl = input(8, "Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 long_call_ts = last_high * (1 - tsl) long_call_tsi = last_open_longCondition * (1 + tsil) long_ts = isTSl and not na(last_high) and low <= long_call_ts and longCondition == 0 and last_high >= long_call_tsi isTSs = false //input(false, "Trailing Stop Short") tsis = 25 //input(25, "Activate Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 tss = 8 //input(8, "Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 short_call_ts = last_low * (1 + tss) short_call_tsi = last_open_shortCondition * (1 - tsis) short_ts = isTSs and not na(last_low) and high >= short_call_ts and shortCondition == 0 and last_low <= short_call_tsi // === /END // === Create Single Close For All Closing Conditions === closelong = long_sl or long_ts or longX closeshort = short_sl or short_ts or shortX // Get Last Close last_long_close := closelong ? time : nz(last_long_close[1]) last_short_close := closeshort ? time : nz(last_short_close[1]) // Check For Close Since Last Open if closelong and last_long_close[1] > last_longCondition closelong := false if closeshort and last_short_close[1] > last_shortCondition closeshort := false // === /END //////////////////////////////////////////////////////////////////////////// // === Alarm Settings === //alertcondition(longCondition==1, title='LONG', message='LONG') //alertcondition(closelong==1, title='EXIT LONG', message='EXIT LONG') //alertcondition(shortCondition==1, title='SHORT', message='SHORT') //alertcondition(closeshort==1, title='EXIT SHORT', message='EXIT SHORT') // === /END //////////////////////////////////////////////////////////////////////////// // === Visuals & Debugs Here === //Remove "//" To Check/Debug The Code Above // Signal Shapes //plotshape(longCondition[1]==1, title='LONG', style=shape.triangleup, size=size.large, color=#02CB80, location= location.belowbar) //plotshape(shortCondition[1]==1, title='SHORT', style=shape.triangledown, size=size.large, color=#DC143C, location=location.abovebar) //plotshape(shortCondition[1]==0 and closelong[1]==1, title='EXIT LONG', style=shape.xcross, color=#02CB80, location=location.belowbar, transp=0) //plotshape(longCondition[1]==0 and closeshort[1]==1, title='EXIT SHORT', style=shape.xcross, color=#DC143C, location=location.abovebar, transp=0) // SL Plot //slColor = (isSLl or isSLs) and (in_longCondition or in_shortCondition) ? red : white //plot(isSLl and in_longCondition ? long_call_sl : na, "Long SL", slColor, style=3, linewidth=2) //plot(isSLs and in_shortCondition ? short_call_sl : na, "Short SL", slColor, style=3, linewidth=2) // TP Plot //tpColor = isTP and (in_longCondition or in_shortCondition) ? purple : white //plot(isTP and in_longCondition ? long_call_tp : na, "Long TP", tpColor, style=3, linewidth=2) //plot(isTP and in_shortCondition ? short_call_tp : na, "Short TP", tpColor, style=3, linewidth=2) // TS Plot //tsColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? orange : white //tsiColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? white : orange //plot(isTSl and in_longCondition ? long_call_tsi : na, "Long Trailing", tsiColor, style=3, linewidth=2) //plot(isTSs and in_shortCondition ? short_call_tsi : na, "Short Trailing", tsiColor, style=3, linewidth=2) //plot(isTSl and in_longCondition and last_high > long_call_tsi ? long_call_ts : na, "Long Trailing", tsColor, style=2, linewidth=2) //plot(isTSs and in_shortCondition and last_low < short_call_tsi ? short_call_ts : na, "Short Trailing", tsColor, style=2, linewidth=2) // === /END //////////////////////////////////////////////////////////////////////////// // // // REMOVE THE CODE BELOW FOR STUDY CONVERSION // // // //////////////////////////////////////////////////////////////////////////// // === Strategy Direction Switch === dir = "Long" //input(title = "Strategy Direction", defval="Long") //, options=["Long", "Short", "Both"] // === /END // === Backtesting Dates === testPeriodSwitch = input(false, "Custom Backtesting Dates") testStartYear = input(2017, "Backtest Start Year") testStartMonth = input(1, "Backtest Start Month") testStartDay = input(1, "Backtest Start Day") testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,0,0) testStopYear = input(9999, "Backtest Stop Year") testStopMonth = input(1, "Backtest Stop Month") testStopDay = input(1, "Backtest Stop Day") testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay,0,0) testPeriod() => time >= testPeriodStart and time <= testPeriodStop ? true : false isPeriod = testPeriodSwitch == true ? testPeriod() : true // === /END // === Strategy === if isPeriod and dir=="Both" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) and not shortCondition strategy.close("Long") if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) and not longCondition strategy.close("Short") if isPeriod and dir=="Long" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) strategy.close("Long") if isPeriod and dir=="Short" if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) strategy.close("Short") // === /END //////////////////////////////////////////////////////////////////////////// // // // ULTIMATE PINE INJECTOR V1.2 // // // //////////////////////===ANION=CODE=END====///////////////////////////////// ================================================ FILE: extensions/strategies/ehlers_mama/strategy.js ================================================ /* ======= Ehlers MESA Adaptive Moving Average ======= Developed by John Ehlers, the MESA Adaptive Moving Average is a technical trend-following indicator which, according to its creator, adapts to price movement “based on the rate change of phase as measured by the Hilbert Transform Discriminator”. This method of adaptation features a fast and a slow moving average so that the composite moving average swiftly responds to price changes and holds the average value until the next bar’s close. Ehlers states that because the average’s fallback is slow, you can create trading systems with almost whipsaw-free trades. Basically the indicator looks like two moving averages, but instead of curving around the price action, the MESA Adaptive MA moves in a staircase manner as the price ratchets. It produces two outputs, MAMA and FAMA. FAMA (Following Adaptive Moving Average) is a result of MAMA being applied to the first MAMA line. The FAMA is synchronized in time with MAMA, but its vertical movement comes with a lag. Thus, the two don’t cross unless a major change in market direction occurs, resulting in a moving average crossover system which is “virtually free of whipsaw trades”, according to Ehlers. If you appreciate the work and the man hours that went into creating this strategy, please consider giving back. LoneWolf345 ETH = 0xa42f6d21f1e52f7fbaeaa0f58d1cc4b9a58f2dcc , BTC = 15L8QstCQG4ho6139hVaqLxkAzcjnqBbf6 Travis ETH = 0xdA963A127BeCB08227583d11f912F400D5347060 , BTC = 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW */ let z = require('zero-fill'), n = require('numbro'), Phenotypes = require('../../../lib/phenotype'), crossover = require('../../../lib/helpers').crossover, crossunder = require('../../../lib/helpers').crossunder, nz = require('../../../lib/helpers').nz, iff = require('../../../lib/helpers').iff, tv = require('../../../lib/helpers') module.exports = { name: 'Ehlers MAMA', description: 'Ehlers MESA Adaptive Moving Average', getOptions: function() { this.option('period', 'period length eg 10m', String, '60m') this.option('min_periods', 'min. number of history periods', Number, 6) // this.option('mama_periods', '', Number, 5) this.option('mama_fastlimit', '', Number, 0.5) this.option('mama_slowlimit', '', Number, 0.09) this.option('price_source', '', String, 'HAohlc4') }, calculate: function() {}, onPeriod: function(s, cb) { if (!s.mama) { s.mama = { src: [], sp: [], dt: [], q1: [], i1: [], i2: [], q2: [], re: [], im: [], p: [], p1: [], p3: [], spp: [], phase: [], mama: [], fama: [] } } if (s.lookback.length > s.options.min_periods) { if(!s.options.price_source || s.options.price_source === 'close'){ s.mama.src.unshift(s.period.close) } else if (s.options.price_source === 'hl2'){ s.mama.src.unshift(tv.hl2(s.period)) } else if (s.options.price_source === 'hlc3'){ s.mama.src.unshift(tv.hlc3(s.period)) } else if (s.options.price_source === 'ohlc4'){ s.mama.src.unshift(tv.ohlc4(s.period)) } else if (s.options.price_source === 'HAohlc4'){ s.mama.src.unshift(tv.HAohlc4(s)) } //s.mama.src.unshift((s.period.high + s.period.low) / 2) s.mama.sp.unshift((4 * s.mama.src[0] + 3 * s.mama.src[1] + 2 * s.mama.src[2] + s.mama.src[3]) / 10.0) s.mama.dt.unshift((.0962 * s.mama.sp[0] + .5769 * nz(s.mama.sp[2]) - .5769 * nz(s.mama.sp[4]) - .0962 * nz(s.mama.sp[6])) * (.075 * nz(s.mama.p[0]) + .54)) s.mama.q1.unshift((.0962 * s.mama.dt[0] + .5769 * nz(s.mama.dt[2]) - .5769 * nz(s.mama.dt[4]) - .0962 * nz(s.mama.dt[6])) * (.075 * nz(s.mama.p[0]) + .54)) s.mama.i1.unshift(nz(s.mama.dt[3])) let jI = (.0962 * s.mama.i1[0] + .5769 * nz(s.mama.i1[2]) - .5769 * nz(s.mama.i1[4]) - .0962 * nz(s.mama.i1[6])) * (.075 * nz(s.mama.p[0]) + .54) let jq = (.0962 * s.mama.q1[0] + .5769 * nz(s.mama.q1[2]) - .5769 * nz(s.mama.q1[4]) - .0962 * nz(s.mama.q1[6])) * (.075 * nz(s.mama.p[0]) + .54) let i2_ = s.mama.i1[0] - jq let q2_ = s.mama.q1[0] + jI s.mama.i2.unshift(.2 * i2_ + .8 * nz(s.mama.i2[0])) s.mama.q2.unshift(.2 * q2_ + .8 * nz(s.mama.q2[0])) let re_ = s.mama.i2[0] * nz(s.mama.i2[1]) + s.mama.q2[0] * nz(s.mama.q2[1]) let im_ = s.mama.i2[0] * nz(s.mama.q2[1]) - s.mama.q2[0] * nz(s.mama.i2[1]) s.mama.re.unshift(.2 * re_ + .8 * nz(s.mama.re[0])) s.mama.im.unshift(.2 * im_ + .8 * nz(s.mama.im[0])) s.mama.p1.unshift(iff(s.mama.im[0] != 0 && s.mama.re[0] != 0, 360 / Math.atan(s.mama.im[0] / s.mama.re[0]), nz(s.mama.p[0]))) let p2 = iff(s.mama.p1[0] > 1.5 * nz(s.mama.p1[1]), 1.5 * nz(s.mama.p1[1]), iff(s.mama.p1[0] < 0.67 * nz(s.mama.p1[1]), 0.67 * nz(s.mama.p1[1]), s.mama.p1[0])) s.mama.p3.unshift(iff(p2 < 6, 6, iff(p2 > 50, 50, p2))) s.mama.p.unshift(.2 * s.mama.p3[0] + .8 * nz(s.mama.p3[1])) s.mama.spp.unshift(.33 * s.mama.p[0] + .67 * nz(s.mama.spp[0])) s.mama.phase.unshift(Math.atan(s.mama.q1[0] / s.mama.i1[0])) let dphase_ = nz(s.mama.phase[1]) - s.mama.phase[0] let dphase = iff(dphase_ < 1, 1, dphase_) let alpha_ = s.options.mama_fastlimit / dphase let alpha = iff(alpha_ < s.options.mama_slowlimit, s.options.mama_slowlimit, iff(alpha_ > s.options.mama_fastlimit, s.options.mama_fastlimit, alpha_)) s.mama.mama.unshift(alpha * s.mama.src[0] + (1 - alpha) * nz(s.mama.mama[0])) s.mama.fama.unshift(.5 * alpha * s.mama.mama[0] + (1 - .5 * alpha) * nz(s.mama.fama[0])) s.period.mama = s.mama.mama[0] if (s.options.debug) {console.log('s.mama.mama: ' + s.mama.mama[0])} s.period.fama = s.mama.fama[0] if (s.mama.src.length > 7) Object.keys(s.mama).forEach(k => { s.mama[k].pop() }) if (!s.in_preroll) { if (crossover(s, 'mama', 'fama')) s.signal = 'buy' else if (crossunder(s, 'mama', 'fama')) s.signal = 'sell' else s.signal = null } } cb() }, onReport: function(s) { var cols = [] let color = 'cyan' let FamaMamaDelta = (s.period.mama - s.period.fama) / s.period.mama * 100 if (s.period.fama < s.period.mama) { color = 'green' } else if (s.period.fama > s.period.mama) { color = 'red' } cols.push(z(10, '[' + n(FamaMamaDelta).format('#00.##') + '%]', '')[color]) cols.push(z(10, 'M[' + n(s.period.mama).format('###.0') + ']', '')[color]) cols.push(z(10, ' F[' + n(s.period.fama).format('###.0') + ']', '')[color]) return cols }, phenotypes: { //General Options period_length: Phenotypes.RangePeriod(5, 240, 'm'), min_periods: Phenotypes.Range(10, 10), markdown_buy_pct: Phenotypes.RangeFloat(0, 0), markup_sell_pct: Phenotypes.RangeFloat(0, 0), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range(1, 20), profit_stop_pct: Phenotypes.Range(1, 10), //Strategy Specific mama_fastlimit: Phenotypes.RangeFactor(0.1, 0.9, 0.1), mama_slow_limit: Phenotypes.RangeFactor(0.01, 0.09, 0.01), price_source: Phenotypes.ListOption(['hl2', 'hlc3', 'ohlc4', 'HAohlc4']) } } ================================================ FILE: extensions/strategies/ehlers_trend/README.md ================================================ ======= Ehlers Instantaneous Trend ======= If you appreciate the work and the man hours that went into creating this strategy, please consider giving back. LoneWolf345 ETH = 0xa42f6d21f1e52f7fbaeaa0f58d1cc4b9a58f2dcc , BTC = 15L8QstCQG4ho6139hVaqLxkAzcjnqBbf6 Travis ETH = 0xdA963A127BeCB08227583d11f912F400D5347060 , BTC = 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW ===== Trading View Script ===== //@version=2 strategy(title="Ehlers Instantaneous Trend", shorttitle="Ehlers IT", overlay=true, precision=3, initial_capital=1000) // === INPUTS src=input(hl2, title="Source") a= input(0.07, title="Alpha", step=0.01) fr=input(true, title="Fill Trend Region") ebc=input(false, title="Enable barcolors") hr=input(false, title="Hide Ribbon") pa=input(true, title="Arrow Markers") // === /INPUTS // === FUNCTIONS it=(a-((a*a)/4.0))*src+0.5*a*a*src[1]-(a-0.75*a*a)*src[2]+2*(1-a )*nz(it[1], ((src+2*src[1]+src[2])/4.0))-(1-a )*(1-a )*nz(it[2], ((src+2*src[1]+src[2])/4.0)) lag=2.0*it-nz(it[2]) dl=plot(fr and (not hr)?(it>lag?lag:it):na, color=gray, style=circles, linewidth=0, title="Dummy") itl=plot(hr?na:it, color=fr?gray:red, linewidth=1, title="Trend") ll=plot(hr?na:lag, color=fr?gray:blue, linewidth=1, title="Trigger") plotarrow(pa?(cross(it, lag)?laglag?red:lime) barcolor(bc) // === Upgraded Conditions Framework === //////////////////////////////////////////////////////////////////////////// long_entry = cross(it, lag)?lag>it?true:false:false short_entry = cross(it, lag)?lag last_shortCondition and last_longCondition >= last_longClose in_shortCondition = last_shortCondition > last_longCondition and last_shortCondition >= last_shortClose // === /END // === Stop Loss (Long) === isSLl = input(false, "Stop Loss (Long)") sll = input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 long_call_sl = last_open_longCondition * (1 - sll) long_sl = isSLl and low <= long_call_sl and longCondition == 0 // === /END // === Stop Loss (Short) === isSLs = false //input(false, "Stop Loss (Short)") sls = 6 //input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 short_call_sl = last_open_shortCondition * (1 + sls) short_sl = isSLs and high >= short_call_sl and shortCondition == 0 // === /END // === Trailing Stop === last_high = na last_low = na last_high := in_longCondition ? (na(last_high[1]) or high > nz(last_high[1])) ? high : nz(last_high[1]) : na last_low := in_shortCondition ? (na(last_low[1]) or low < nz(last_low[1])) ? low : nz(last_low[1]) : na isTSl = input(false, "Trailing Stop Long") tsil = input(25, "Activate Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 tsl = input(8, "Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 long_call_ts = last_high * (1 - tsl) long_call_tsi = last_open_longCondition * (1 + tsil) long_ts = isTSl and not na(last_high) and low <= long_call_ts and longCondition == 0 and last_high >= long_call_tsi isTSs = false //input(false, "Trailing Stop Short") tsis = 25 //input(25, "Activate Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 tss = 8 //input(8, "Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 short_call_ts = last_low * (1 + tss) short_call_tsi = last_open_shortCondition * (1 - tsis) short_ts = isTSs and not na(last_low) and high >= short_call_ts and shortCondition == 0 and last_low <= short_call_tsi // === /END // === Create Single Close For All Closing Conditions === closelong = long_sl or long_ts or longX closeshort = short_sl or short_ts or shortX // Get Last Close last_long_close := closelong ? time : nz(last_long_close[1]) last_short_close := closeshort ? time : nz(last_short_close[1]) // Check For Close Since Last Open if closelong and last_long_close[1] > last_longCondition closelong := false if closeshort and last_short_close[1] > last_shortCondition closeshort := false // === /END //////////////////////////////////////////////////////////////////////////// // === Alarm Settings === //alertcondition(longCondition==1, title='LONG', message='LONG') //alertcondition(closelong==1, title='EXIT LONG', message='EXIT LONG') //alertcondition(shortCondition==1, title='SHORT', message='SHORT') //alertcondition(closeshort==1, title='EXIT SHORT', message='EXIT SHORT') // === /END //////////////////////////////////////////////////////////////////////////// // === Visuals & Debugs Here === //Remove "//" To Check/Debug The Code Above // Signal Shapes //plotshape(longCondition[1]==1, title='LONG', style=shape.triangleup, size=size.large, color=#02CB80, location= location.belowbar) //plotshape(shortCondition[1]==1, title='SHORT', style=shape.triangledown, size=size.large, color=#DC143C, location=location.abovebar) //plotshape(shortCondition[1]==0 and closelong[1]==1, title='EXIT LONG', style=shape.xcross, color=#02CB80, location=location.belowbar, transp=0) //plotshape(longCondition[1]==0 and closeshort[1]==1, title='EXIT SHORT', style=shape.xcross, color=#DC143C, location=location.abovebar, transp=0) // SL Plot //slColor = (isSLl or isSLs) and (in_longCondition or in_shortCondition) ? red : white //plot(isSLl and in_longCondition ? long_call_sl : na, "Long SL", slColor, style=3, linewidth=2) //plot(isSLs and in_shortCondition ? short_call_sl : na, "Short SL", slColor, style=3, linewidth=2) // TP Plot //tpColor = isTP and (in_longCondition or in_shortCondition) ? purple : white //plot(isTP and in_longCondition ? long_call_tp : na, "Long TP", tpColor, style=3, linewidth=2) //plot(isTP and in_shortCondition ? short_call_tp : na, "Short TP", tpColor, style=3, linewidth=2) // TS Plot //tsColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? orange : white //tsiColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? white : orange //plot(isTSl and in_longCondition ? long_call_tsi : na, "Long Trailing", tsiColor, style=3, linewidth=2) //plot(isTSs and in_shortCondition ? short_call_tsi : na, "Short Trailing", tsiColor, style=3, linewidth=2) //plot(isTSl and in_longCondition and last_high > long_call_tsi ? long_call_ts : na, "Long Trailing", tsColor, style=2, linewidth=2) //plot(isTSs and in_shortCondition and last_low < short_call_tsi ? short_call_ts : na, "Short Trailing", tsColor, style=2, linewidth=2) // === /END //////////////////////////////////////////////////////////////////////////// // // // REMOVE THE CODE BELOW FOR STUDY CONVERSION // // // //////////////////////////////////////////////////////////////////////////// // === Strategy Direction Switch === dir = "Long" //input(title = "Strategy Direction", defval="Long") //, options=["Long", "Short", "Both"] // === /END // === Backtesting Dates === testPeriodSwitch = input(false, "Custom Backtesting Dates") testStartYear = input(2017, "Backtest Start Year") testStartMonth = input(1, "Backtest Start Month") testStartDay = input(1, "Backtest Start Day") testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,0,0) testStopYear = input(9999, "Backtest Stop Year") testStopMonth = input(1, "Backtest Stop Month") testStopDay = input(1, "Backtest Stop Day") testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay,0,0) testPeriod() => time >= testPeriodStart and time <= testPeriodStop ? true : false isPeriod = testPeriodSwitch == true ? testPeriod() : true // === /END // === Strategy === if isPeriod and dir=="Both" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) and not shortCondition strategy.close("Long") if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) and not longCondition strategy.close("Short") if isPeriod and dir=="Long" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) strategy.close("Long") if isPeriod and dir=="Short" if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) strategy.close("Short") // === /END //////////////////////////////////////////////////////////////////////////// // // // ULTIMATE PINE INJECTOR V1.2 // // // //////////////////////===ANION=CODE=END====///////////////////////////////// ================================================ FILE: extensions/strategies/ehlers_trend/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , Phenotypes = require('../../../lib/phenotype') , crossover = require('../../../lib/helpers').crossover , crossunder = require('../../../lib/helpers').crossunder , nz = require('../../../lib/helpers').nz , tv = require('../../../lib/helpers') module.exports = { name: 'Ehlers_Trend', description: 'Ehlers Instantaneous Trend', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') this.option('alpha', '', Number, 0.07) this.option('price_source', '', String, 'HAohlc4') }, calculate: function () {}, onPeriod: function (s, cb) { if (s.lookback.length > s.options.min_periods) { if(!s.options.price_source || s.options.price_source === 'close'){ s.period.src = s.period.close } else if (s.options.price_source === 'hl2'){ s.period.src = tv.hl2(s) } else if (s.options.price_source === 'hlc3'){ s.period.src = tv.hlc3(s) } else if (s.options.price_source === 'ohlc4'){ s.period.src = tv.ohlc4(s) } else if (s.options.price_source === 'HAhlc3'){ s.period.src = tv.HAhlc3(s) } else if (s.options.price_source === 'HAohlc4'){ s.period.src = tv.HAohlc4(s) } let a = s.options.alpha if (s.lookback.length < 7) { s.period.trend = (s.period.src + 2 * nz(s.lookback[0].src) + nz(s.lookback[1].src)) / 4 } else { s.period.trend = (a-a*a/4.0)*s.period.src+0.5*a*a*nz(s.lookback[0].src)-(a-0.75*a*a)*nz(s.lookback[1].src)+2*(1-a)*nz(s.lookback[0].trend) - (1-a)*(1-a)*nz(s.lookback[1].trend) s.period.trigger = 2.0*s.period.trend-nz(s.lookback[1].trend) } } if(crossover(s, 'trend', 'trigger')) s.signal = 'sell' else if(crossunder(s, 'trend', 'trigger')) s.signal = 'buy' else s.signal = null cb() }, onReport: function (s) { var cols = [] let color = 'cyan' if (s.period.trend > s.period.trigger) { color = 'red' } else if (s.period.trend < s.period.trigger) { color = 'green' } cols.push(z(10, 'Trend[' + n(s.period.trend).format('###.0') + ']', '')[color]) cols.push(z(10, ' trigger[' + n(s.period.trigger).format('###.0') + ']', '')[color]) return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(15, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFloat(-1, 3), markup_sell_pct: Phenotypes.RangeFloat(-1, 3), order_type: Phenotypes.ListOption(['maker', 'taker']), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), //Strategy Specific alpha: Phenotypes.RangeFactor(0.01, 0.2, 0.01) } } ================================================ FILE: extensions/strategies/ichimoku/strategy.js ================================================ var z = require('zero-fill'), n = require('numbro'), highest = require('../../../lib/highest'), lowest = require('../../../lib/lowest'), Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ichimoku', description: 'Ichimoku Cloud', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '4h') this.option('period_length', 'period length', String, '4h') this.option('min_periods', 'min periods (should be >= senkou_b option)', Number, 52) this.option('tenkan', 'Tenkan (conversion) line', Number, 9) this.option('kijun','Kijun (base) line', Number, 26) this.option('senkou_b','Senkou (leading) span B', Number, 52) this.option('chikou','Chikou (lagging) span)', Number, 26) }, calculate: function (s) { }, onPeriod: function (s, cb) { if (s.lookback[s.options.min_periods]) { highest(s, 'tenkan_high', s.options.tenkan) lowest(s, 'tenkan_low', s.options.tenkan) highest(s, 'kijun_high', s.options.kijun) lowest(s, 'kijun_low', s.options.kijun) highest(s, 'senkou_high', s.options.senkou_b) lowest(s, 'senkou_low', s.options.senkou_b) s.period.tenkan = ((s.period.tenkan_high + s.period.tenkan_low) / 2) s.period.kijun = ((s.period.kijun_high + s.period.kijun_low) / 2) s.period.senkou_a = ((s.period.tenkan + s.period.kijun) / 2) s.period.senkou_b = ((s.period.senkou_high + s.period.senkou_low) / 2) s.period.chikou = s.lookback[s.options.chikou - 1].close // The below lines cause the bot to buy when the price is above the kumo cloud and sell when the price is inside // or below the kumo cloud. There are many different ways to trade the Ichimoku Cloud and all of them can be // implemented using the indicators above. if (s.period.close > Math.max(s.period.senkou_a, s.period.senkou_b)) { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null } if (s.period.close < Math.max(s.period.senkou_a, s.period.senkou_b)) { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } } cb() }, onReport: function (s) { var cols = [] return cols }, phenotypes: { //General Options period_length: Phenotypes.RangePeriod(5, 120, 'm'), min_periods: Phenotypes.Range(150, 150), //(should be >= senkou_b option) markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), //Strategy Specific tenkan: Phenotypes.RangeFactor(5, 30, 1), kijun: Phenotypes.RangeFactor(25, 75, 1), senkou_b: Phenotypes.RangeFactor(50, 150, 1), chikou: Phenotypes.RangeFactor(20, 40, 1) } } ================================================ FILE: extensions/strategies/ichimoku_score/README.md ================================================ ======= Ichimoku Signals Score ======= The Ichimoku signals, indeed all Ichimoku elements, should never be taken in isolation, but considered in the context of the overall chart. Ichimoku Kinko Hyo is a visual technical analysis system and the charts are designed to be considered in their entirety, with regard given to the relationships between all of the elements, including the price. As such, Ichimoku is not suitable for automated or "single event" decision making. Remember that Ichimoku Kinko Hyo is a technical trend trading charting system and trends can and do change, so your readings of the charts should be probabilistic, rather than predictive. As with most technical analysis methods, Ichimoku is likely to produce frequent conflicting signals in non-trending markets. The five kinds of signal are described below. Most can be classified as strong, neutral, or weak by their proximate relationship to the Kumo (cloud), but each signal may be further strengthened, weakened, or nullified by the relationships between other elements. All signals must be considered in respect to the overall chart. For a better understanding of how to read ichimoku please refer to http://www.ichimokutrader.com/signals.html Code based on a TradingView.com script at https://www.tradingview.com/v/u0NN8zNu/ If you appreciate the work and the man hours that went into creating this strategy, please consider giving back. LoneWolf345 ETH = 0xa42f6d21f1e52f7fbaeaa0f58d1cc4b9a58f2dcc , BTC = 15L8QstCQG4ho6139hVaqLxkAzcjnqBbf6 Travis ETH = 0xdA963A127BeCB08227583d11f912F400D5347060 , BTC = 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW ======= Trading View Strategy Script ======= //@version=2 //study(title="Ichimoku Cloud Score LW", shorttitle="Ichimoku Score", precision=3, overlay=false) strategy(title="Ichimoku Cloud Signal Score", shorttitle="Ichimoku Score", precision=3, overlay=false) // == ichimoku inputs == tenkenSenPeriods = input(9, minval=1, title="Tenkan-sen (Conversion Line) Periods"), kijunSenPeriods = input(26, minval=1, title="Kijun-sen (Base Line) Periods") senkouSpanPeriods = input(52, minval=1, title="Senkou (Leading) Span B Periods"), displacement = input(26, minval=1, title="Displacement") // == score inputs == tkCrossWeight = input(1.0, title="TK Cross Importance Weight", type=float, step=0.1) pkCrossWeight = input(1.0, title="PK Cross Importance Weight", type=float, step=0.1) kumoBreakoutWeight = input(1.0, title="Kumo Breakout Importance Weight", type=float, step=0.1) senkouCrossWeight = input(1.0, title="Senkou (Leading) Span Cross Importance Weight", type=float, step=0.1) chikouCrossWeight = input(1.0, title="Chikou (Lagging) Span Cross Importance Weight", type=float, step=0.1) chikouPlacementWeight = input(1.0, title="Chikou (Lagging) Span Relative to Cloud Importance Weight", type=float, step=0.1) pricePlacementWeight = input(1.0, title="Price Relative to Cloud Importance Weight", type=float, step=0.1) weakPoints = input(0.5, title="Weak Point Value", type=float, step=0.1) neutralPoints = input(1.0, title="Neutral Point Value", type=float, step=0.1) strongPoints = input(2.0, title="Strong Point Value", type=float, step=0.1) // == helpers == donchian(len) => avg(lowest(len), highest(len)) resolve(src, default) => na(src) ? default : src getIntersect(series1, series2) => (series1[1] * (series2 - series2[1]) - series2[1] * (series1 - series1[1])) / ((series2 - series2[1]) - (series1 - series1[1])) belowKumo(val, senkou1, senkou2) => val < senkou1[1] and val < senkou2[1] and val < senkou1 and val < senkou2 aboveKumo(val, senkou1, senkou2) => val > senkou1[1] and val > senkou2[1] and val > senkou1 and val > senkou2 insideKumo(val, senkou1, senkou2) => (not belowKumo(val, senkou1, senkou2)) and (not aboveKumo(val, senkou1, senkou2)) // == generate ichimoku data == tenkanSen = donchian(tenkenSenPeriods) kijunSen = donchian(kijunSenPeriods) chikouSen = offset(close, -displacement) senkouA = offset(avg(tenkanSen, kijunSen), displacement) senkouB = offset(donchian(senkouSpanPeriods), displacement) priceAboveKumo = aboveKumo(close, senkouA, senkouB) priceBelowKumo = belowKumo(close, senkouA, senkouB) priceInsideKumo = insideKumo(close, senkouA, senkouB) // == ichimoku cloud signals == // source: http://www.ichimokutrader.com/signals.html // == Tenkan Sen (turning line) / Kijun Sen (standard line) Cross == calcTkCross(previousVal) => bullish = crossover(tenkanSen, kijunSen) bearish = crossunder(tenkanSen, kijunSen) intersect = getIntersect(tenkanSen, kijunSen) above = aboveKumo(intersect, senkouA, senkouB) below = belowKumo(intersect, senkouA, senkouB) inside = insideKumo(intersect, senkouA, senkouB) score = resolve(previousVal, 0) score := (bullish and below) ? weakPoints : score score := (bullish and inside) ? neutralPoints : score score := (bullish and above) ? strongPoints : score score := (bearish and below) ? -strongPoints : score score := (bearish and inside) ? -neutralPoints : score score := (bearish and above) ? -weakPoints : score score // == Price and Kijun Sen (standard line) Cross == calcPkCross(previousVal) => bullish = crossover(close, kijunSen) bearish = crossunder(close, kijunSen) intersect = getIntersect(close, kijunSen) above = aboveKumo(intersect, senkouA, senkouB) below = belowKumo(intersect, senkouA, senkouB) inside = insideKumo(intersect, senkouA, senkouB) score = resolve(previousVal, 0) score := (bullish and below) ? weakPoints : score score := (bullish and inside) ? neutralPoints : score score := (bullish and above) ? strongPoints : score score := (bearish and below) ? -strongPoints : score score := (bearish and inside) ? -neutralPoints : score score := (bearish and above) ? -weakPoints : score score // == Kumo Breakouts == calcKumoBreakout(previousVal) => bullish = (crossover(close, senkouA) and senkouA >= senkouB) or (crossover(close, senkouB) and senkouB >= senkouA) bearish = (crossunder(close, senkouB) and senkouA >= senkouB) or (crossunder(close, senkouA) and senkouB >= senkouA) score = resolve(previousVal, 0) score := bullish ? strongPoints : score score := bearish ? -strongPoints : score score // == Senkou Span Cross == // The Senkou Span Cross signal occurs when the Senkou Span A (1st leading line) crosses the Senkou Span B (2nd leading line). // NOTE: this cross occurs ahead of the price, since it's displaced to the right; this displacement must be removed calcSenkouCross(previousVal) => noDpsenkouA = avg(tenkanSen, kijunSen) // Senkou Span A (no displacement) noDpsenkouB = donchian(senkouSpanPeriods) // Senkou Span B (no displacement) bullish = crossover(noDpsenkouA, noDpsenkouB) bearish = crossunder(noDpsenkouA, noDpsenkouB) score = resolve(previousVal, 0) score := (bullish and priceBelowKumo) ? weakPoints : score score := (bullish and priceInsideKumo) ? neutralPoints : score score := (bullish and priceAboveKumo) ? strongPoints : score score := (bearish and priceBelowKumo) ? -strongPoints : score score := (bearish and priceInsideKumo) ? -neutralPoints : score score := (bearish and priceAboveKumo) ? -weakPoints : score score // == Chikou Span Cross == // The Chikou Span Cross signal occurs when the Chikou Span (Lagging line) rises above or falls below the price. calcChikouCross(previousVal) => // think in terms of current price = chikouSen leadLine = offset(close, displacement) bullish = crossover(close, leadLine) bearish = crossunder(close, leadLine) score = resolve(previousVal, 0) score := (bullish and priceBelowKumo) ? weakPoints : score score := (bullish and priceInsideKumo) ? neutralPoints : score score := (bullish and priceAboveKumo) ? strongPoints : score score := (bearish and priceBelowKumo) ? -strongPoints : score score := (bearish and priceInsideKumo) ? -neutralPoints : score score := (bearish and priceAboveKumo) ? -weakPoints : score score // == price relative to cloud == calcPricePlacement(previousVal) => score = resolve(previousVal, 0) score := priceAboveKumo ? strongPoints : score score := priceInsideKumo ? 0 : score score := priceBelowKumo ? -strongPoints : score score // == lag line releative to cloud == calcChikouPlacement(previousVal) => // doing calculation based on left-shifted chikouSen caused errors. // Instead we shift the kumo right again and do comparison based on current price shiftedSenkouA = offset(senkouA, displacement) shiftedSenkouB = offset(senkouB, displacement) score = resolve(previousVal, 0) score := aboveKumo(close, shiftedSenkouA, shiftedSenkouB) ? strongPoints : score score := insideKumo(close, shiftedSenkouA, shiftedSenkouB) ? 0 : score score := belowKumo(close, shiftedSenkouA, shiftedSenkouB) ? -strongPoints : score score // == plot score == tkCrossScore = calcTkCross(tkCrossScore[1]) pkCrossScore = calcPkCross(pkCrossScore[1]) kumoBreakoutScore = calcKumoBreakout(kumoBreakoutScore[1]) senkouCrossScore = calcSenkouCross(senkouCrossScore[1]) chikouCrossScore = calcChikouCross(chikouCrossScore[1]) pricePlacementScore = calcPricePlacement(pricePlacementScore[1]) chikouPlacementScore = calcChikouPlacement(chikouPlacementScore[1]) totalScore = (tkCrossWeight * tkCrossScore) totalScore := totalScore + (pkCrossWeight * pkCrossScore) totalScore := totalScore + (kumoBreakoutWeight * kumoBreakoutScore) totalScore := totalScore + (senkouCrossWeight * senkouCrossScore) totalScore := totalScore + (chikouCrossWeight * chikouCrossScore) totalScore := totalScore + (pricePlacementWeight * pricePlacementScore) totalScore := totalScore + (chikouPlacementWeight * chikouPlacementScore) maxScore = strongPoints * (tkCrossWeight + pkCrossWeight + kumoBreakoutWeight + senkouCrossWeight + chikouCrossWeight + pricePlacementWeight + chikouPlacementWeight) normalizedScore = 100 * totalScore / maxScore base = hline(50, color=gray, linestyle=solid, linewidth=2, title="Base") max = hline(100, color=gray, linestyle=solid, title="Max") min = hline(-100, color=gray, linestyle=solid, title="Min") fill(max, base, color=green, title="Bullish") fill(min, base, color=red, title="Bearish") plot(normalizedScore, color=orange, linewidth=3, title="Total Score") // // == plot ichimoku == // // Tenkan Sen (turning line) (blue) //plot(tenkanSen, color=blue, title="Tenkan Sen (Turning/Conversion Line)", linewidth=3) // // Kijun Sen (base/standard line) (red) //plot(kijunSen, color=red, title="Kijun Sen (Standard/Base Line)", linewidth=3) // // Chikou Span (lagging line) (green) //plot(close, offset = -displacement, color=green, title="Chikou Span (Lagging Span)", linewidth=3) // // Senkou Span A //renderSenkouA = avg(tenkanSen, kijunSen) // used only for rendering below //p1 = plot(renderSenkouA, offset = displacement, color=green, title="Senkou Span (Leading Span) A") // // Senkou Span B //renderSenkouB = donchian(senkouSpanPeriods) // used only for rendering below //p2 = plot(renderSenkouB, offset = displacement, color=red, title="Senkou Span (Leading Span) B") // // i.e. Kumo cloud colouring //fill(p1, p2, color = renderSenkouA > renderSenkouB ? green : red) // // == strategy moves == //simulateBuys = input(true, title="Simulate Buys") buyThreshold = input(80.0, title="Buy Threshold", type=float, step=0.1) sellThreshold = input(50.0, title="Sell Threshold", type=float, step=0.1) buyCondition = normalizedScore > buyThreshold sellCondition = normalizedScore < sellThreshold //strategy.entry("buy", true, 1, when = buyCondition) //strategy.close("buy", when = sellCondition) // === Upgraded Conditions Framework === //////////////////////////////////////////////////////////////////////////// long_entry = buyCondition == true short_entry = sellCondition == true long_exit = short_entry //Close Long Condition Here (Optional) short_exit = long_entry //Close Short Condition Here (Optional) /////////////////////////////////////////////////////////////////////////// // init these values here, they will get updated later as more decisions are made last_long_close = na last_short_close = na // === Long position detection === // longs open longo = 0 longo := nz(longo[1]) // longs closed longc = 0 longc := nz(longc[1]) if long_entry longo := longo + 1 longc := 0 if long_exit longc := longc + 1 longo := 0 // === /END // === Short position detection === shorto = 0 shorto := nz(shorto[1]) shortc = 0 shortc := nz(shortc[1]) if short_entry shorto := shorto + 1 shortc := 0 if short_exit shortc := shortc + 1 shorto := 0 // === /END // === Pyramiding Settings === pyr = input(1, title="Pyramiding Setting") //pyr = 1 longCondition = long_entry and longo <= pyr longX = long_exit and longc <= pyr shortCondition = short_entry and shorto <=pyr shortX = short_exit and shortc <=pyr // === /END // === Get Last Position Price === last_open_longCondition = na last_open_shortCondition = na // last open prices last_open_longCondition := longCondition ? close : nz(last_open_longCondition[1]) last_open_shortCondition := shortCondition ? close : nz(last_open_shortCondition[1]) // === /END // === Check For Long/Short === last_longCondition = na last_shortCondition = na // last open times last_longCondition := longCondition ? time : nz(last_longCondition[1]) last_shortCondition := shortCondition ? time : nz(last_shortCondition[1]) last_longClose = longX ? time : nz(last_long_close[1]) last_shortClose = shortX ? time : nz(last_short_close[1]) in_longCondition = last_longCondition > last_shortCondition and last_longCondition >= last_longClose in_shortCondition = last_shortCondition > last_longCondition and last_shortCondition >= last_shortClose // === /END // === Stop Loss (Long) === isSLl = input(false, "Stop Loss (Long)") sll = input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 long_call_sl = last_open_longCondition * (1 - sll) long_sl = isSLl and low <= long_call_sl and longCondition == 0 // === /END // === Stop Loss (Short) === isSLs = input(false, "Stop Loss (Short)") sls = input(6, "Stop Loss %", type=float, step=0.2, minval=0, maxval=100) / 100 short_call_sl = last_open_shortCondition * (1 + sls) short_sl = isSLs and high >= short_call_sl and shortCondition == 0 // === /END // === Trailing Stop === last_high = na last_low = na last_high := in_longCondition ? (na(last_high[1]) or high > nz(last_high[1])) ? high : nz(last_high[1]) : na last_low := in_shortCondition ? (na(last_low[1]) or low < nz(last_low[1])) ? low : nz(last_low[1]) : na isTSl = input(false, "Trailing Stop Long") tsil = input(25, "Activate Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 tsl = input(8, "Trailing Stop % Long", type=float, step=1, minval=0, maxval=100) / 100 long_call_ts = last_high * (1 - tsl) long_call_tsi = last_open_longCondition * (1 + tsil) long_ts = isTSl and not na(last_high) and low <= long_call_ts and longCondition == 0 and last_high >= long_call_tsi isTSs = input(false, "Trailing Stop Short") tsis = input(25, "Activate Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 tss = input(8, "Trailing Stop % Short", type=float, step=1, minval=0, maxval=100) / 100 short_call_ts = last_low * (1 + tss) short_call_tsi = last_open_shortCondition * (1 - tsis) short_ts = isTSs and not na(last_low) and high >= short_call_ts and shortCondition == 0 and last_low <= short_call_tsi // === /END // === Create Single Close For All Closing Conditions === closelong = long_sl or long_ts or longX closeshort = short_sl or short_ts or shortX // Get Last Close last_long_close := closelong ? time : nz(last_long_close[1]) last_short_close := closeshort ? time : nz(last_short_close[1]) // Check For Close Since Last Open if closelong and last_long_close[1] > last_longCondition closelong := false if closeshort and last_short_close[1] > last_shortCondition closeshort := false // === /END //////////////////////////////////////////////////////////////////////////// // === Alarm Settings === //alertcondition(longCondition==1, title='LONG', message='LONG') //alertcondition(closelong==1, title='EXIT LONG', message='EXIT LONG') //alertcondition(shortCondition==1, title='SHORT', message='SHORT') //alertcondition(closeshort==1, title='EXIT SHORT', message='EXIT SHORT') // === /END //////////////////////////////////////////////////////////////////////////// // === Visuals & Debugs Here === //Remove "//" To Check/Debug The Code Above // Signal Shapes //plotshape(longCondition[1]==1, title='LONG', style=shape.triangleup, size=size.large, color=#02CB80, location= location.belowbar) //plotshape(shortCondition[1]==1, title='SHORT', style=shape.triangledown, size=size.large, color=#DC143C, location=location.abovebar) //plotshape(shortCondition[1]==0 and closelong[1]==1, title='EXIT LONG', style=shape.xcross, color=#02CB80, location=location.belowbar, transp=0) //plotshape(longCondition[1]==0 and closeshort[1]==1, title='EXIT SHORT', style=shape.xcross, color=#DC143C, location=location.abovebar, transp=0) // SL Plot //slColor = (isSLl or isSLs) and (in_longCondition or in_shortCondition) ? red : white //plot(isSLl and in_longCondition ? long_call_sl : na, "Long SL", slColor, style=3, linewidth=2) //plot(isSLs and in_shortCondition ? short_call_sl : na, "Short SL", slColor, style=3, linewidth=2) // TP Plot //tpColor = isTP and (in_longCondition or in_shortCondition) ? purple : white //plot(isTP and in_longCondition ? long_call_tp : na, "Long TP", tpColor, style=3, linewidth=2) //plot(isTP and in_shortCondition ? short_call_tp : na, "Short TP", tpColor, style=3, linewidth=2) // TS Plot //tsColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? orange : white //tsiColor = (isTSl or isTSs) and (in_longCondition or in_shortCondition) ? white : orange //plot(isTSl and in_longCondition ? long_call_tsi : na, "Long Trailing", tsiColor, style=3, linewidth=2) //plot(isTSs and in_shortCondition ? short_call_tsi : na, "Short Trailing", tsiColor, style=3, linewidth=2) //plot(isTSl and in_longCondition and last_high > long_call_tsi ? long_call_ts : na, "Long Trailing", tsColor, style=2, linewidth=2) //plot(isTSs and in_shortCondition and last_low < short_call_tsi ? short_call_ts : na, "Short Trailing", tsColor, style=2, linewidth=2) // === /END //////////////////////////////////////////////////////////////////////////// // // // REMOVE THE CODE BELOW FOR STUDY CONVERSION // // // //////////////////////////////////////////////////////////////////////////// // === Strategy Direction Switch === dir = input(title = "Strategy Direction", defval="Long") //, options=["Long", "Short", "Both"] // === /END // === Backtesting Dates === testPeriodSwitch = input(false, "Custom Backtesting Dates") testStartYear = input(2017, "Backtest Start Year") testStartMonth = input(1, "Backtest Start Month") testStartDay = input(1, "Backtest Start Day") testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,0,0) testStopYear = input(9999, "Backtest Stop Year") testStopMonth = input(1, "Backtest Stop Month") testStopDay = input(1, "Backtest Stop Day") testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay,0,0) testPeriod() => time >= testPeriodStart and time <= testPeriodStop ? true : false isPeriod = testPeriodSwitch == true ? testPeriod() : true // === /END // === Strategy === if isPeriod and dir=="Both" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) and not shortCondition strategy.close("Long") if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) and not longCondition strategy.close("Short") if isPeriod and dir=="Long" if (longCondition) strategy.entry("Long",strategy.long) if (closelong) strategy.close("Long") if isPeriod and dir=="Short" if (shortCondition) strategy.entry("Short",strategy.short) if (closeshort) strategy.close("Short") // === /END //////////////////////////////////////////////////////////////////////////// // // // ULTIMATE PINE INJECTOR V1.2 // // // //////////////////////===ANION=CODE=END====///////////////////////////////// ================================================ FILE: extensions/strategies/ichimoku_score/strategy.js ================================================ // ======= Ichimoku Signals Score ======= /* The Ichimoku signals, indeed all Ichimoku elements, should never be taken in isolation, but considered in the context of the overall chart. Ichimoku Kinko Hyo is a visual technical analysis system and the charts are designed to be considered in their entirety, with regard given to the relationships between all of the elements, including the price. As such, Ichimoku is not suitable for automated or "single event" decision making. Remember that Ichimoku Kinko Hyo is a technical trend trading charting system and trends can and do change, so your readings of the charts should be probabilistic, rather than predictive. As with most technical analysis methods, Ichimoku is likely to produce frequent conflicting signals in non-trending markets. The five kinds of signal are described below. Most can be classified as strong, neutral, or weak by their proximate relationship to the Kumo (cloud), but each signal may be further strengthened, weakened, or nullified by the relationships between other elements. All signals must be considered in respect to the overall chart. For a better understanding of how to read ichimoku please refer to http://www.ichimokutrader.com/signals.html Code based on a TradingView.com script at https://www.tradingview.com/v/u0NN8zNu/ If you appreciate the work and the man hours that went into creating this strategy, please consider giving back. LoneWolf345 ETH = 0xa42f6d21f1e52f7fbaeaa0f58d1cc4b9a58f2dcc , BTC = 15L8QstCQG4ho6139hVaqLxkAzcjnqBbf6 Travis ETH = 0xdA963A127BeCB08227583d11f912F400D5347060 , BTC = 3KKHdBJpEGxghxGazoE4X7ihyr2q6nHUvW */ let z = require('zero-fill') , n = require('numbro') , Phenotypes = require('../../../lib/phenotype') , crossover = require('../../../lib/helpers').crossover , crossunder = require('../../../lib/helpers').crossunder module.exports = { name: 'ichimoku_score', description: 'Associate various ichimoku signals with a score.', getOptions: function () { this.option('period', 'period length eg 10m', String, '60m') this.option('min_periods', 'min. number of history periods', Number, 150) // == ichimoku inputs == this.option('tenkenSenPeriods', 'Tenkan-sen (Conversion Line) Periods', Number, 9) //default 9 this.option('kijunSenPeriods', 'Kijun-sen (Base Line) Periods', Number, 26) //default 26 this.option('senkouSpanPeriods', 'Senkou (Leading) Span B Periods', Number, 52) //default 52 this.option('displacement', 'Displacement', Number, 26) //default 26 // == score inputs == this.option('tkCrossWeight', 'TK Cross Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('pkCrossWeight', 'PK Cross Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('kumoBreakoutWeight', 'Kumo Breakout Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('senkouCrossWeight', 'Senkou (Leading) Span Cross Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('chikouCrossWeight', 'Chikou (Lagging) Span Cross Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('chikouPlacementWeight', 'Chikou (Lagging) Span Relative to Cloud Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('pricePlacementWeight', 'Price Relative to Cloud Importance Weight', Number, 1) //range 0 - 2 Default = 1 this.option('weakPoints', 'Weak Point Value', Number, 0.5) //range 0 - 2 Default = 0.5 this.option('neutralPoints', 'Neutral Point Value', Number, 1) //range 0 - 2 Default = 1 this.option('strongPoints', 'Strong Point Value', Number, 2) //range 0 - 2 Default = 2 this.option('buyLevel', 'when to signal buy', Number, 50) //range -100 - 100 Default = 50 this.option('sellLevel', 'when to signal sell', Number, 49) //range -100 - 100 Default = 50 }, calculate: function (s) { if (s.lookback.length > s.options.min_periods) { // == == generate ichimoku data == == s.period.tenkenSen = donchian(s, s.options.tenkenSenPeriods) s.period.kijunSen = donchian(s, s.options.kijunSenPeriods) s.period.senkouA = (s.period.tenkenSen + s.period.kijunSen) / 2 s.period.senkouB = donchian(s, s.options.senkouSpanPeriods) // have to wait until displacement periods have passed if (s.lookback.length > s.options.displacement) { s.lookback[s.options.displacement].chikouSen = s.period.close s.priceAboveKumo = valueAbove(s.period.close, s.period.senkouA, s.period.senkouB) s.priceBelowKumo = valueBelow(s.period.close, s.period.senkouA, s.period.senkouB) s.priceInsideKumo = !s.priceAboveKumo && !s.priceBelowKumo // == == calculate score == == s.period.tkCrossScore = calcTkCross(s, s.lookback[0].tkCrossScore) s.period.pkCrossScore = calcPkCross(s, s.lookback[0].pkCrossScore) s.period.kumoBreakoutScore = calcKumoBreakout(s, s.lookback[0].kumoBreakoutScore) s.period.senkouCrossScore = calcSenkouCross(s, s.lookback[0].senkouCrossScore) s.period.chikouCrossScore = calcChikouCross(s, s.lookback[0].chikouCrossScore) s.period.pricePlacementScore = calcPricePlacement(s, s.lookback[0].pricePlacementScore) s.period.chikouPlacementScore = calcChikouPlacement(s, s.lookback[0].chikouPlacementScore) s.totalScore = (s.options.tkCrossWeight * s.period.tkCrossScore) s.totalScore += (s.options.pkCrossWeight * s.period.pkCrossScore) s.totalScore += (s.options.kumoBreakoutWeight * s.period.kumoBreakoutScore) s.totalScore += (s.options.senkouCrossWeight * s.period.senkouCrossScore) s.totalScore += (s.options.chikouCrossWeight * s.period.chikouCrossScore) s.totalScore += (s.options.pricePlacementWeight * s.period.pricePlacementScore) s.totalScore += (s.options.chikouPlacementWeight * s.period.chikouPlacementScore) let maxScore = s.options.strongPoints * (s.options.tkCrossWeight + s.options.pkCrossWeight + s.options.kumoBreakoutWeight + s.options.senkouCrossWeight + s.options.chikouCrossWeight + s.options.pricePlacementWeight + s.options.chikouPlacementWeight) s.normalizedScore = 100 * s.totalScore / maxScore } } }, onPeriod: function (s, cb) { // == Debugging == if (s.options.debug) {console.log('\n== Options ==')} if (s.options.debug) {console.log('tenkenSenPeriods: ' + s.options.tenkenSenPeriods)} if (s.options.debug) {console.log('kijunSenPeriods: ' + s.options.kijunSenPeriods)} if (s.options.debug) {console.log('senkouSpanPeriods: ' + s.options.senkouSpanPeriods)} if (s.options.debug) {console.log('displacement: ' + s.options.displacement)} if (s.options.debug) {console.log('buyLevel: ' + s.options.buyLevel)} if (s.options.debug) {console.log('sellLevel: ' + s.options.sellLevel)} if (s.options.debug) {console.log('\n== Ichimoku Data ==')} if (s.options.debug) {console.log('Tenken-Sen (conversion Line):' + s.period.tenkenSen)} if (s.options.debug) {console.log('Kijun-Sen (Base Line):' + s.period.kijunSen)} if (s.options.debug) {console.log('senkouA (Leading):' + s.period.senkouA)} if (s.options.debug) {console.log('senkouB (Leading):' + s.period.senkouB)} if (s.options.debug) {console.log('\n== Calculate Score ==')} if (s.options.debug) {console.log('tkCrossScore:' + s.period.tkCrossScore)} if (s.options.debug) {console.log('pkCrossScore:' + s.period.pkCrossScore)} if (s.options.debug) {console.log('kumoBreakoutScore:' + s.period.kumoBreakoutScore)} if (s.options.debug) {console.log('senkouCrossScore:' + s.period.senkouCrossScore)} if (s.options.debug) {console.log('chikouCrossScore:' + s.period.chikouCrossScore)} if (s.options.debug) {console.log('pricePlacementScore:' + s.period.pricePlacementScore)} if (s.options.debug) {console.log('chikouPlacementScore:' + s.period.chikouPlacementScore)} if (s.options.debug) {console.log('\n== Buy / Sell signals ==')} if (s.options.debug) {console.log('normalizedScore:' + s.normalizedScore)} if (s.options.debug) {console.log('previousScore:' + s.previousScore)} if (s.options.debug) {console.log('buy logic')} if (s.options.debug) {console.log('if (s.normalizedScore > s.options.buyLevel && s.previousScore < s.options.buyLevel)')} if (s.options.debug) {console.log('if (' + s.normalizedScore + ' > ' + s.options.buyLevel + ' && ' + s.previousScore + ' < ' + s.options.buyLevel + ')')} if (s.options.debug) {console.log(s.normalizedScore > s.options.buyLevel && s.previousScore < s.options.buyLevel)} // == == Buy / Sell Signals == == if (!s.previousScore) {s.previousScore = 0} if (s.normalizedScore > s.options.buyLevel && s.previousScore < s.options.buyLevel) { s.signal = 'buy' s.previousScore = s.normalizedScore } else if (s.normalizedScore > s.options.sellLevel && s.previousScore > s.options.buyLevel && s.previousScore < s.options.sellLevel) { s.signal = 'buy' s.previousScore = s.normalizedScore } else if (s.normalizedScore < s.options.sellLevel && s.previousScore > s.options.sellLevel) { s.signal = 'sell' s.previousScore = s.normalizedScore } else { s.signal = null s.previousScore = s.normalizedScore } cb() }, onReport: function (s) { var cols = [] let color = 'cyan' if (s.normalizedScore > 50) { color = 'green' } else if (s.normalizedScore < -50) { color = 'red' } cols.push(z(10, 'S[' + n(s.normalizedScore).format('###.0') + ']', '')[color]) return cols }, phenotypes: { //General Options period_length: Phenotypes.RangePeriod(45, 240, 'm'), min_periods: Phenotypes.Range(150, 150), //Needs to be greater than senkouSpanPeriods markdown_buy_pct: Phenotypes.RangeFloat(0, 0), markup_sell_pct: Phenotypes.RangeFloat(0, 0), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range(1, 20), profit_stop_pct: Phenotypes.Range(1,10), //Strategy Specific buyLevel: Phenotypes.RangeFactor(5, 100, 5), sellLevel: Phenotypes.RangeFactor(5, 100, 5), tenkenSenPeriods: Phenotypes.RangeFactor(5, 30, 1), kijunSenPeriods: Phenotypes.RangeFactor(25, 75, 1), senkouSpanPeriods: Phenotypes.RangeFactor(50, 150, 1), displacement: Phenotypes.RangeFactor(20, 40, 1) } } // == == Helpers == == function resolve(src, fallback) { return isNaN(src) ? fallback : src} function donchian(s, len) { let data = s.lookback.slice(0, len - 1), lowData = [s.period.low, ...data.map(p => p.low)], highData = [s.period.high, ...data.map(p => p.high)] return (Math.min(...lowData) + Math.max(...highData)) / 2 } function getIntersect(s, key1, key2) { return (s.lookback[0][key1] * (s.period[key2] - s.lookback[0][key2]) - s.lookback[0][key2] * (s.period[key1] - s.lookback[0][key1])) / ((s.period[key2] - s.lookback[0][key2]) - (s.period[key1] - s.lookback[0][key1])) } function belowKumo(s, key, key1, key2) { return valueBelowKumo(s, s.period[key], key1, key2) } function aboveKumo(s, key, key1, key2) { return valueAboveKumo(s, s.period[key], key1, key2) } function valueBelowKumo(s, val, key1, key2) { if(s.lookback.length >= s.options.displacement) return valueBelow(val, s.lookback[s.options.displacement][key1], s.lookback[s.options.displacement][key2]) else throw 'belowKumo, s.lookback.length < s.options.displacement' } function valueAboveKumo(s, val, key1, key2) { if(s.lookback.length >= s.options.displacement) return valueAbove(val, s.lookback[s.options.displacement][key1], s.lookback[s.options.displacement][key2]) else throw 'aboveKumo, s.lookback.length < s.options.displacement' } function valueAbove(val, target1, target2) { return val > Math.max(target1, target2) } function valueBelow(val, target1, target2) { return val < Math.min(target1, target2) } // == == ichimoku cloud signals == == // == Tenkan Sen (turning line) / Kijun Sen (standard line) Cross == function calcTkCross(s, previousVal) { let bullish = crossover(s, 'tenkenSen', 'kijunSen') let bearish = crossunder(s, 'tenkenSen', 'kijunSen') let intersect = getIntersect(s, 'tenkenSen', 'kijunSen') let above = valueAboveKumo(s, intersect, 'senkouA', 'senkouB') let below = valueBelowKumo(s, intersect, 'senkouA', 'senkouB') let inside = !above && !below let score = resolve(previousVal, 0) if (bullish && below) {score = s.options.weakPoints} //A weak bullish signal occurs when the cross is below the Kumo. if (bullish && inside) {score = s.options.neutralPoints} //A neutral bullish signal occurs when the cross is inside the Kumo. if (bullish && above) {score = s.options.strongPoints} //A strong bullish signal occurs when the cross is above the Kumo. if (bearish && below) {score = -s.options.strongPoints} //A strong bearish signal occurs when the cross is below the Kumo. if (bearish && inside) {score = -s.options.neutralPoints} //A neutral bearish signal occurs when the cross is inside the Kumo. if (bearish && above) {score = -s.options.weakPoints} //A weak bearish signal occurs when the cross is above the Kumo. return (score) } // == Price and Kijun Sen (standard line) Cross == function calcPkCross(s, previousVal) { let bullish = crossover(s, 'close', 'kijunSen') let bearish = crossunder(s, 'close', 'kijunSen') let intersect = getIntersect(s, 'close', 'kijunSen') let above = valueAboveKumo(s, intersect, 'senkouA', 'senkouB') let below = valueBelowKumo(s, intersect, 'senkouA', 'senkouB') let inside = !above && !below let score = resolve(previousVal, 0) if (bullish && below) {score = s.options.weakPoints} //A weak bullish signal occurs when the cross is below the Kumo. if (bullish && inside) {score = s.options.neutralPoints} //A neutral bullish signal occurs when the cross is inside the Kumo. if (bullish && above) {score = s.options.strongPoints} //A strong bullish signal occurs when the cross is above the Kumo. if (bearish && below) {score = -s.options.strongPoints} //A strong bearish signal occurs when the cross is below the Kumo. if (bearish && inside) {score = -s.options.neutralPoints} //A neutral bearish signal occurs when the cross is inside the Kumo. if (bearish && above) {score = -s.options.weakPoints} //A weak bearish signal occurs when the cross is above the Kumo. return (score) } // == Kumo Breakouts == function calcKumoBreakout(s, previousVal) { let bullish = (crossover(s, 'close', 'senkouA') && s.period.senkouA >= s.period.senkouB) || (crossover(s, 'close', 'senkouB') && s.senkouB >= s.senkouA) let bearish = (crossunder(s, 'close', 'senkouB') && s.period.senkouA >= s.period.senkouB) || (crossover(s, 'close', 'senkouA') && s.senkouB >= s.senkouA) let score = resolve(previousVal, 0) if (bullish) {score = s.options.strongPoints} //A bullish signal occurs when the price goes upwards through the top of the Kumo. if (bearish) {score = -s.options.strongPoints} //A bearish signal occurs when the price goes downwards through the bottom of the Kumo. return (score) } // == Senkou Span Cross == // The Senkou Span Cross signal occurs when the Senkou Span A (1st leading line) crosses the Senkou Span B (2nd leading line). // NOTE: this cross occurs ahead of the price, since it's displaced to the right; this displacement must be removed function calcSenkouCross(s, previousVal) { s.period.noDpsenkouA = (s.period.tenkenSen + s.period.kijunSen) / 2 //Senkou Span A (no displacement) s.period.noDpsenkouB = donchian(s, s.options.senkouSpanPeriods) //senkou Span B (no displacement) let bullish = crossover(s, 'noDpsenkouA', 'noDpsenkouB') let bearish = crossunder(s, 'noDpsenkouA', 'noDpsenkouB') let score = resolve(previousVal, 0) if (bullish && s.priceBelowKumo) {score = s.options.weakPoints} //A weak bullish signal occurs if the current price is below the Kumo. if (bullish && s.priceInsideKumo) {score = s.options.neutralPoints} //A neutral bullish signal occurs if the current price is inside the Kumo. if (bullish && s.priceAboveKumo) {score = s.options.strongPoints} //A strong bullish signal occurs if the current price is above the Kumo. if (bearish && s.priceBelowKumo) {score = -s.options.strongPoints} //A strong bearish signal occurs if the current price is below the Kumo. if (bearish && s.priceInsideKumo) {score = -s.options.neutralPoints} //A neutral bearish signal occurs if the current price is inside the Kumo. if (bearish && s.priceAboveKumo) {score = -s.options.weakPoints} //A weak bearish signal occurs if the current price is above the Kumo. return (score) } // == Chikou Span Cross == // The Chikou Span Cross signal occurs when the Chikou Span (Lagging line) rises above or falls below the price. function calcChikouCross(s, previousVal) { s.period.leadline = s.lookback[s.options.displacement].close//offset(s.period.close, s.options.displacement) let bullish = crossover(s, 'close', 'leadline') let bearish = crossunder(s, 'close', 'leadline') let score = resolve(previousVal, 0) if (bullish && s.priceBelowKumo) {score = s.options.weakPoints} //A weak bullish signal occurs if the current price is below the Kumo. if (bullish && s.priceInsideKumo) {score = s.options.neutralPoints} //A neutral bullish signal occurs if the current price is inside the Kumo. if (bullish && s.priceAboveKumo) {score = s.options.strongPoints} //A strong bullish signal occurs if the current price is above the Kumo. if (bearish && s.priceBelowKumo) {score = -s.options.strongPoints} //A weak bearish signal occurs if the current price is above the Kumo. if (bearish && s.priceInsideKumo) {score = -s.options.neutralPoints} //A neutral bearish signal occurs if the current price is inside the Kumo. if (bearish && s.priceAboveKumo) {score = -s.options.weakPoints} //A strong bearish signal occurs if the current price is below the Kumo. return (score) } // == price relative to cloud == function calcPricePlacement(s, previousVal) { let score = resolve(previousVal, 0) if (s.priceAboveKumo) {score = s.options.strongPoints} if (s.priceInsideKumo) {score = s.options.neutralPoints} if (s.priceBelowKumo) {score = -s.options.strongPoints} return (score) } // == lag line releative to cloud == function calcChikouPlacement(s, previousVal) { let score = resolve(previousVal, 0) if(s.lookback.length >= s.options.displacement) { // above if(aboveKumo(s, 'close', 'senkouA', 'senkouB')) score = s.options.strongPoints // below else if(belowKumo(s, 'close', 'senkouA', 'senkouB')) score = -s.options.strongPoints else score = 0 } return (score) } ================================================ FILE: extensions/strategies/kc/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , kc = require('../../../lib/kc') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'kc', description: 'Buy when (Signal ≤ Lower Keltner Channel) and sell when (Signal ≥ Upper Keltner Channel).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('kc_size', 'period size', Number, 20) this.option('kc_multiplier', 'multiplier for the average true range', Number, 1) this.option('kc_upper_channel_pct', 'pct the current price should be near the keltner upper channel before we sell', Number, 0) this.option('kc_lower_channel_pct', 'pct the current price should be near the keltner lower channel before we buy', Number, 0) }, calculate: function (s) { // calculate Keltner Channels kc(s, 'kc', s.options.kc_size) }, onPeriod: function (s, cb) { if (s.period.kc) { if (s.period.kc.upper && s.period.kc.lower) { let upperChannel = s.period.kc.upper[s.period.kc.upper.length-1] let lowerChannel = s.period.kc.lower[s.period.kc.lower.length-1] if (s.period.close > (upperChannel / 100) * (100 - s.options.kc_upper_channel_pct)) { s.signal = 'sell' } else if (s.period.close < (lowerChannel / 100) * (100 + s.options.kc_lower_channel_pct)) { s.signal = 'buy' } else { s.signal = null // hold } } } cb() }, onReport: function (s) { var cols = [] if (s.period.kc) { if (s.period.kc.upper && s.period.kc.lower) { let upperChannel = s.period.kc.upper[s.period.kc.upper.length-1] let lowerChannel = s.period.kc.lower[s.period.kc.lower.length-1] var color = 'grey' if (s.period.close > (upperChannel / 100) * (100 - s.options.kc_upper_channel_pct)) { color = 'green' } else if (s.period.close < (lowerChannel / 100) * (100 + s.options.kc_lower_channel_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerChannel).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperChannel).format('0.000000').substring(0,7), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy kc_size: Phenotypes.Range(1, 40), kc_upper_channel_pct: Phenotypes.RangeFloat(-1, 30), kc_lower_channel_pct: Phenotypes.RangeFloat(-1, 30) } } ================================================ FILE: extensions/strategies/macd/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , ema = require('../../../lib/ema') , rsi = require('../../../lib/rsi') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'macd', description: 'Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 12) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 26) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } // compute MACD ema(s, 'ema_short', s.options.ema_short_period) ema(s, 'ema_long', s.options.ema_long_period) if (s.period.ema_short && s.period.ema_long) { s.period.macd = (s.period.ema_short - s.period.ema_long) ema(s, 'signal', s.options.signal_period, 'macd') if (s.period.signal) { s.period.macd_histogram = s.period.macd - s.period.signal } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.trend = 'overbought' s.signal = 'sell' return cb() } } if (typeof s.period.macd_histogram === 'number' && typeof s.lookback[0].macd_histogram === 'number') { if ((s.period.macd_histogram - s.options.up_trend_threshold) > 0 && (s.lookback[0].macd_histogram - s.options.up_trend_threshold) <= 0) { s.signal = 'buy' } else if ((s.period.macd_histogram + s.options.down_trend_threshold) < 0 && (s.lookback[0].macd_histogram + s.options.down_trend_threshold) >= 0) { s.signal = 'sell' } else { s.signal = null // hold } } cb() }, onReport: function (s) { var cols = [] if (typeof s.period.macd_histogram === 'number') { var color = 'grey' if (s.period.macd_histogram > 0) { color = 'green' } else if (s.period.macd_histogram < 0) { color = 'red' } cols.push(z(8, n(s.period.macd_histogram).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.overbought_rsi).format('00'), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy ema_short_period: Phenotypes.Range(1, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), up_trend_threshold: Phenotypes.Range(0, 50), down_trend_threshold: Phenotypes.Range(0, 50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/momentum/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , momentum = require('../../../lib/momentum') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'momentum', description: 'MOM = Close(Period) - Close(Length)', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('momentum_size', 'number of periods to look back for momentum', Number, 5) }, calculate: function (s) { if (s.in_preroll) { return } momentum(s, 'mom0', 'close', s.options.momentum_size) momentum(s, 'mom1', 'mom0', 1) }, onPeriod: function (s, cb) { if (s.in_preroll) { cb() return } if (s.period.mom0 > 0 && s.period.mom1 > 0) { s.signal = 'buy' } if (s.period.mom0 < 0 && s.period.mom1 < 0) { s.signal = 'sell' } cb() }, onReport: function (s) { let cols = [], color if (s.period.mom0 != null) { color = s.period.mom0 < 0 ? 'red' : s.period.mom0 > 0 ? 'green' : 'grey' cols.push(z(5, n(s.period.mom0).format('000'), ' ')[color]) } else { cols.push(' '.repeat(5)) } if (s.period.mom1 != null) { color = s.period.mom1 < 0 ? 'red' : s.period.mom1 > 0 ? 'green' : 'grey' cols.push(z(5, n(s.period.mom1).format('000'), ' ')[color]) } else { cols.push(' '.repeat(5)) } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 2500), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy momentum_size: Phenotypes.Range(1,20) } } ================================================ FILE: extensions/strategies/multi/strategy.js ================================================ var pivot = require('../pivot/strategy') var macd = require('../macd/strategy') var ehlers_ft = require('../ehlers_ft/strategy') var momentum = require('../momentum/strategy') var Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'multi', description: 'This strategy utilize: pivot macd momentum ehlers_ft.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') // PIVOT // this.option('period_length', 'period length', String, '30m') this.option('min_periods', 'min periods', Number, 50) this.option('up', 'up', Number, 1) this.option('down','down', Number, 1) // MACD / TA_MACD //this.option('period', 'period length, same as --period_length', String, '1h') //this.option('period_length', 'period length, same as --period', String, '1h') //this.option('min_periods', 'min. number of history periods', Number, 52) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 12) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 26) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) // ETHLERS_FT //this.option('period', 'period length, same as --period_length', String, '30m') //this.option('period_length', 'period length, same as --period', String, '30m') this.option('fish_pct_change', 'percent change of fisher transform for reversal', Number, 0) this.option('length', 'number of past periods to use including current', Number, 10) this.option('src', 'use period.close if not defined. can be hl2, hlc3, ohlc4, HAhlc3, HAohlc4', String, 'hl2') this.option('pos_length', 'check this number of previous periods have opposing pos value', Number, 1) // MOMENTUM //this.option('period', 'period length, same as --period_length', String, '1h') //this.option('period_length', 'period length, same as --period', String, '1h') this.option('momentum_size', 'number of periods to look back for momentum', Number, 5) }, calculate: function (s) { pivot.calculate(s) macd.calculate(s) ehlers_ft.calculate(s) momentum.calculate(s) }, onPeriod: function (s, cb) { let totalBuy = 0 let totalSell = 0 if(s && s.lookback && s.lookback.constructor === Array && s.lookback.length > 5 && s.lookback[1].high && s.lookback[5].high) { pivot.onPeriod(s, function(){}) if(s.signal == 'buy') totalBuy += 1 if(s.signal == 'sell') totalSell += 1 } macd.onPeriod(s, function(){}) if(s.signal == 'buy') totalBuy += 1 if(s.signal == 'sell') totalSell += 1 ehlers_ft.onPeriod(s, function(){}) if(s.signal == 'buy') totalBuy += 1 if(s.signal == 'sell') totalSell += 1 momentum.onPeriod(s, function(){}) if(s.signal == 'buy') totalBuy += 1 if(s.signal == 'sell') totalSell += 1 s.signal = null if(totalBuy >= 2 && totalBuy >= totalSell && totalSell == 0) s.signal = 'buy' if(totalSell >= 2 && totalSell >= totalBuy && totalBuy == 0) s.signal = 'sell' if(s.signal == 'buy' && s.stopTriggered) { s.stopTriggered = false } if(s.signal == 'sell' && s.stopTriggered) { s.signal = null } return cb() }, onReport: function (s) { var cols = [] return cols.concat(pivot.onReport(s), macd.onReport(s), ehlers_ft.onReport(s), momentum.onReport(s)) }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 60, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), //sell_stop_pct: Phenotypes.Range0(1, 50), //buy_stop_pct: Phenotypes.Range0(1, 50), //profit_stop_enable_pct: Phenotypes.Range0(1, 20), //profit_stop_pct: Phenotypes.Range(1,20), sell_stop_pct: Phenotypes.RangeFloat(0.4, 0.6), //profit_stop_enable_pct: Phenotypes.RangeFloat(0.5, 1), //quarentine_time: Phenotypes.ListOption([240, 270, 300]), // macd ema_short_period: Phenotypes.Range(1, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), up_trend_threshold: Phenotypes.Range(0, 50), down_trend_threshold: Phenotypes.Range(0, 50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100), // ehlers_ft length: Phenotypes.Range(1, 30), fish_pct_change: Phenotypes.Range(-25, 75), pos_length: Phenotypes.Range(1, 6), src: Phenotypes.ListOption(['close', 'hl2', 'hlc3', 'ohlc4', 'HAhlc3', 'HAohlc4']), // momentum momentum_size: Phenotypes.Range(1,20) } } ================================================ FILE: extensions/strategies/neural/README.md ================================================ ## Reading the console output ![console](Capture.PNG) From left to right ( for trendline not pictured above, which is neural ): - Timestamp in local time (grey, blue when showing "live" stats) - Asset price in currency (yellow) - Percent change of price since last period (red/green) - Volume in asset since last period (grey) - [RSI](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi) ANSI graph (red/green) - strategy inormation, in order: ``` - col1: current last trade price - col2: The old trade last trade price averaged with the prediction. - If the predicted price and average of last trade price exceeds the current last trade price, then buy.. Like a neural-trendline. ``` - Current signal or action, including `buy`, `sell`, `buying`, `selling`, `bought`, `sold` and `last_trade_worth` (percent change in the trend direction since last buy/sell) - Account balance (asset) - Account balance (currency) - Profit or loss percent (can be reset with `--reset_profit`) - Gain or loss vs. buy/hold strategy The signaling for this strategy example: ``` learn(); var item = tlp.reverse(); s.prediction = predict(item) s.mean = s.lookback[0].close s.meanp = math.mean(s.prediction, oldmean) oldmean = s.prediction } // NORMAL onPeriod STUFF here global.meanp = s.meanp global.mean = s.mean //something strange is going on here global.sig0 = global.meanp < global.mean if ( global.sig0 === false ) { s.signal = 'sell' } else if ( global.sig0 === true ) { s.signal = 'buy' } cb() } }, ``` ================================================ FILE: extensions/strategies/neural/strategy.js ================================================ let convnetjs = require('convnetjs') , z = require('zero-fill') , n = require('numbro') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') const cluster = require('cluster') // the below line starts you at 0 threads global.forks = 0 // the below line is for calculating the last mean vs the now mean. var oldmean = 0 module.exports = { name: 'neural', description: 'Use neural learning to predict future price. Buy = mean(last 3 real prices) < mean(current & last prediction)', getOptions: function () { this.option('period', 'Period length - longer gets a better average', String, '30m') this.option('period_length', 'Period length set same as --period', String, '30m') this.option('activation_1_type', 'Neuron Activation Type: sigmoid, tanh, relu', String, 'sigmoid') this.option('neurons_1', 'Neurons in layer 1', Number, 5) this.option('activation_2_type', 'Neuron Activation Type: sigmoid, tanh, relu', String, 'sigmoid') this.option('neurons_2', 'Neurons in layer 2', Number, 5) this.option('depth', 'Generally the same as min_predict for accuracy', Number, 50) this.option('min_periods', 'Periods to train neural network with from', Number, 2000) this.option('min_predict', 'Periods to predict next number from less than min_periods', Number, 50) this.option('momentum', 'momentum of prediction between 0 and 1 - 0 is stock', Number, 0.0) this.option('decay', 'decay of prediction, use teeny tiny increments beteween 0 and 1 - stock', Number, 0.001) this.option('threads', 'Number of processing threads you\'d like to run (best for sim - Possibly broken', Number, 1) this.option('learns', 'Number of times to \'learn\' the neural network with past data', Number, 10) this.option('learningrate', 'The learning rate of the neural network between 0 and 1 - 0.01 is stock', Number, 0.01) }, calculate: function () { }, onPeriod: function (s, cb) { ema(s, 'neural', s.options.neural) if (s.neural === undefined) { // Create the net the first time it is needed and NOT on every run s.neural = { net : new convnetjs.Net(), layer_defs : [ {type:'input', out_sx:5, out_sy:1, out_depth:s.options.depth}, {type:'fc', num_neurons: s.options.neurons_1, activation: s.options.activation_1_type}, {type:'fc', num_neurons: s.options.neurons_2, activation: s.options.activation_2_type}, {type:'regression', num_neurons:5} ], neuralDepth: s.options.depth } s.neural.net.makeLayers(s.neural.layer_defs) s.neural.trainer = new convnetjs.SGDTrainer(s.neural.net, {learning_rate:s.options.learningrate, momentum:s.options.momentum, batch_size:1, l2_decay:s.options.decay}) } if (cluster.isMaster) { ema(s, 'neural', s.options.neural) if (global.forks < s.options.threads) { cluster.fork(); global.forks++ } cluster.on('exit', (code) => { process.exit(code) }) } if (cluster.isWorker) { ema(s, 'neural', s.options.neural) var tlp = [] var tll = [] // this thing is crazy run with trendline placed here. But there needs to be a coin lock so you dont buy late! if (!s.in_preroll && s.lookback[s.options.min_periods]) { var min_predict = s.options.min_predict > s.options.min_periods ? s.options.min_periods : s.options.min_predict for (let i = 0; i < s.options.min_periods; i++) { tll.push(s.lookback[i]) } for (let i = 0; i < min_predict; i++) { tlp.push(s.lookback[i]) } var my_data = tll.reverse() var learn = function () { //Learns for (var j = 0; j < s.options.learns; j++) { for (var i = 0; i < my_data.length - s.neural.neuralDepth; i++) { var data = my_data.slice(i, i + s.neural.neuralDepth) var real_value = my_data[i + s.neural.neuralDepth] var x = new convnetjs.Vol(5, 1, s.neural.neuralDepth, 0) for (var k = 0; k < s.neural.neuralDepth; k++) { x.set(0,0,k,data[k].open) x.set(1,0,k,data[k].close) x.set(2,0,k,data[k].high) x.set(3,0,k,data[k].low) x.set(4,0,k,data[k].volume) } s.neural.trainer.train(x, [real_value.open, real_value.close, real_value.high, real_value.low, real_value.volume]) } } } var predict = function(data) { var x = new convnetjs.Vol(5, 1, s.neural.neuralDepth, 0) for (var k = 0; k < s.neural.neuralDepth; k++) { x.set(0,0,k,data[k].open) x.set(1,0,k,data[k].close) x.set(2,0,k,data[k].high) x.set(3,0,k,data[k].low) x.set(4,0,k,data[k].volume) } var predicted_value = s.neural.net.forward(x) return predicted_value.w[1] // close value - x.set(1,0,k,data[k].close) } learn() var item = tlp.reverse() s.prediction = predict(item) } // NORMAL onPeriod STUFF here global.predi = s.prediction //something strange is going on here global.sig0 = global.predi > oldmean if ( global.sig0 === false ) { s.signal = 'sell' } else if ( global.sig0 === true ) { s.signal = 'buy' } oldmean = global.predi cb() } }, onReport: function () { var cols = [] cols.push(z(8, n(global.predi).format('0000.000000000'), ' ')) return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy neurons_1: Phenotypes.Range(1, 20), neurons_2: Phenotypes.Range(1, 20), activation_1_type: Phenotypes.ListOption(['sigmoid', 'tanh', 'relu']), activation_2_type: Phenotypes.ListOption(['sigmoid', 'tanh', 'relu']), depth: Phenotypes.Range(1, 200), min_predict: Phenotypes.Range(1, 200), // momentum and decay and learning rate are decimals? momentum: Phenotypes.RangeFloat(0, 1), decay: Phenotypes.RangeFloat(0, 1), learns: Phenotypes.Range(1, 500), learningrate: Phenotypes.RangeFloat(0, 1) } } ================================================ FILE: extensions/strategies/noop/strategy.js ================================================ module.exports = { name: 'noop', description: 'Just do nothing. Can be used to e.g. for training the strategy.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') }, calculate: function () { }, onPeriod: function (s, cb) { cb() }, onReport: function () { var cols = [] return cols } } ================================================ FILE: extensions/strategies/pivot/strategy.js ================================================ var z = require('zero-fill'), n = require('numbro') module.exports = { name: 'pivot', description: 'Pivot Reversal Strategy', getOptions: function () { this.option('period_length', 'period length', String, '30m') this.option('min_periods', 'min periods', Number, 50) this.option('up', 'up', Number, 1) this.option('down','down', Number, 1) }, calculate: function (s) { if (s.lookback[s.options.min_periods]) { if (s.lookback[5].high <= s.lookback[1].high && s.lookback[4].high <= s.lookback[1].high && s.lookback[3].high <= s.lookback[1].high && s.lookback[2].high <= s.lookback[1].high && s.lookback[0].high <= s.lookback[1].high && s.period.high <= s.lookback[1].high) { s.pivothigh = s.lookback[1].high } if (s.lookback[3].low >= s.lookback[1].low && s.lookback[2].low >= s.lookback[1].low && s.lookback[0].low >= s.lookback[1].low && s.period.low >= s.lookback[1].low) { s.pivotlow = s.lookback[1].low } } }, onPeriod: function (s, cb) { if (s.lookback[s.options.min_periods]) { if (s.period.high / s.pivothigh > s.options.up) { if (s.trend != 'up') { s.signal = 'buy' } s.trend = 'up' } if (s.period.low / s.pivotlow < s.options.down) { if (s.trend != 'down') { s.signal = 'sell' } s.trend = 'down' } } cb() }, onReport: function (s) { var cols = [] if (s.lookback[s.options.min_periods]) { cols.push(z(8, n(s.pivothigh), ' ')) cols.push(z(1, ' ')) cols.push(z(8, n(s.pivotlow), ' ')) } return cols } } ================================================ FILE: extensions/strategies/renko/strategy.js ================================================ var z = require('zero-fill'), n = require('numbro') module.exports = { name: 'renko', description: 'Renko Reversal Strategy', getOptions: function () { this.option('period_length', 'period length', String, '15m') this.option('min_periods', 'min periods', Number, 200) this.option('bricksize', 'Brick Size', Number, 1) }, calculate: function (s) { if (s.lookback[s.options.min_periods]) { var prclose = Math.round(s.lookback[s.options.min_periods].close) var propen = Math.round(s.lookback[s.options.min_periods].close) } }, onPeriod: function (s, cb) { if (s.lookback[s.options.min_periods]) { // Sources prclose = Math.round(s.lookback[s.options.min_periods].close) propen = Math.round(s.lookback[s.options.min_periods].close) for(var i = 0; i prclose) que = 1 else if (rclose < prclose) que = -1 else que = 0 if (que > 0) { if (s.trend != 'up') { s.signal = 'buy' } s.trend = 'up' } else if (que < 0) { if (s.trend != 'down') { s.signal = 'sell' } s.trend = 'down' } else { s.trend= 'null' } } cb() }, onReport: function (s) { var cols = [] if (s.lookback[s.options.min_periods]) { cols.push(z(8, n(prclose), ' ')) cols.push(z(1, ' ')) cols.push(z(8, n(rclose), ' ')) cols.push(z(1, ' ')) cols.push(z(8, s.trend, ' ')) } return cols } } function renko_close(s, close, prclose, propen){ var type = s.options.bricksize*2 if (close > (prclose + type)) { if (prclose > propen) { return (prclose + s.options.bricksize) } else { return (prclose + type) } } else if (close < (prclose - type)) { if (prclose < propen) { return (prclose - s.options.bricksize) } else { return (prclose - type) } } else { return (prclose) } } function renko_open(s,close,prclose,propen) { var type = s.options.bricksize*2 if (close > prclose) { if (prclose > propen) { return(prclose) } else { return(prclose + type) } } else if (close < prclose) { if (prclose < propen) { return(prclose) } else { return(prclose - type) } } else { return(propen) } } ================================================ FILE: extensions/strategies/rsi/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , Phenotypes = require('../../../lib/phenotype') , Asset_currency = require('../../../lib/engine') module.exports = { name: 'rsi', description: 'Attempts to buy low and sell high by tracking RSI high-water readings.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '2m') this.option('period_length', 'period length, same as --period', String, '2m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('oversold_rsi', 'buy when RSI reaches or drops below this value', Number, 30) this.option('overbought_rsi', 'sell when RSI reaches or goes above this value', Number, 82) this.option('rsi_recover', 'allow RSI to recover this many points before buying', Number, 3) this.option('rsi_drop', 'allow RSI to fall this many points before selling', Number, 0) this.option('rsi_divisor', 'sell when RSI reaches high-water reading divided by this value', Number, 2) }, calculate: function (s) { rsi(s, 'rsi', s.options.rsi_periods) }, onPeriod: function (s, cb) { if (s.in_preroll) return cb() if (typeof s.period.rsi === 'number') { if (s.trend === undefined && s.period.rsi <= s.options.oversold_rsi) { s.rsi_low = s.period.rsi s.trend = 'oversold' } if (s.trend === 'oversold' || s.asset_capital > 0) { s.rsi_low = Math.min(s.rsi_low, s.period.rsi) if (s.period.rsi >= s.rsi_low + s.options.rsi_recover) { s.trend = 'long' s.signal = 'buy' s.rsi_high = s.period.rsi } } if (s.trend !== 'oversold' && s.trend !== 'long' && s.period.rsi >= s.options.overbought_rsi) { s.rsi_high = s.period.rsi s.trend = 'long' } if (s.trend === 'long' || s.currency_capital > 0) { s.rsi_high = Math.max(s.rsi_high, s.period.rsi) if (s.period.rsi <= s.rsi_high / s.options.rsi_divisor) { s.trend = 'short' s.signal = 'sell' } } if (s.trend === 'long' && s.period.rsi >= s.options.overbought_rsi) { s.rsi_high = s.period.rsi s.trend = 'overbought' } if (s.trend === 'overbought' || s.currency_capital > 0) { s.rsi_high = Math.max(s.rsi_high, s.period.rsi) if (s.period.rsi <= s.rsi_high - s.options.rsi_drop) { s.trend = 'short' s.signal = 'sell' } } } cb() }, onReport: function (s) { var cols = [] if (typeof s.period.rsi === 'number') { var color = 'grey' if (s.period.rsi <= s.options.oversold_rsi) { color = 'green' } if (s.period.rsi >= s.options.overbought_rsi) { color = 'red' } cols.push(z(4, n(s.period.rsi).format('0'), ' ')[color]) } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy rsi_periods: Phenotypes.Range(1, 200), oversold_rsi: Phenotypes.Range(1, 100), overbought_rsi: Phenotypes.Range(1, 100), rsi_recover: Phenotypes.Range(1, 100), rsi_drop: Phenotypes.Range(0, 100), rsi_divisor: Phenotypes.Range(1, 10) } } ================================================ FILE: extensions/strategies/sar/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'sar', description: 'Parabolic SAR', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '2m') this.option('period_length', 'period length, same as --period', String, '2m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('sar_af', 'acceleration factor for parabolic SAR', Number, 0.015) this.option('sar_max_af', 'max acceleration factor for parabolic SAR', Number, 0.3) }, calculate: function (s) { if (s.lookback.length >= s.options.min_periods) { if (!s.trend) { if (s.period.high > s.lookback[s.lookback.length - 1].high) { // start with uptrend s.trend = 'up' s.sar = Math.min(s.lookback[1].low, s.lookback[0].low) s.sar_ep = s.period.high s.sar_af = s.options.sar_af for (var idx = 0; idx < s.lookback.length; idx++) { s.sar_ep = Math.max(s.sar_ep, s.lookback[idx].high) } } else { s.trend = 'down' s.sar = Math.max(s.lookback[1].high, s.lookback[0].high) s.sar_ep = s.period.low s.sar_af = s.options.sar_af for (idx = 0; idx < s.lookback.length; idx++) { s.sar_ep = Math.min(s.sar_ep, s.lookback[idx].low) } } } } }, onPeriod: function (s, cb) { if (typeof s.sar === 'number') { if (s.trend === 'up') { s.sar = Math.min(s.lookback[1].low, s.lookback[0].low, s.sar + (s.sar_af * (s.sar_ep - s.sar))) } else { s.sar = Math.max(s.lookback[1].high, s.lookback[0].high, s.sar - (s.sar_af * (s.sar - s.sar_ep))) } if (s.trend === 'down') { if (s.period.high >= s.sar && s.period.close > s.lookback[0].close) { s.trend = 'up' s.signal = 'buy' s.sar_ep = s.period.low s.sar_af = s.options.sar_af s.sar = Math.min(s.lookback[0].low, s.period.low, s.sar + (s.sar_af * (s.sar_ep - s.sar))) } else if (s.period.low < s.sar_ep) { s.sar_ep = s.period.low if (s.sar_af < s.options.sar_max_af) { s.sar_af += s.options.sar_af } } } else if (s.trend === 'up') { if (s.period.low <= s.sar && s.period.close < s.lookback[0].close) { s.trend = 'down' s.signal = 'sell' s.sar_ep = s.period.high s.sar_af = s.options.sar_af s.sar = Math.max(s.lookback[0].high, s.period.high, s.sar - (s.sar_af * (s.sar - s.sar_ep))) } else if (s.period.high > s.sar_ep) { s.sar_ep = s.period.high if (s.sar_af < s.options.sar_max_af) { s.sar_af += s.options.sar_af } } } if (!s.my_trades.length) { s.signal = s.trend === 'up' ? 'buy' : 'sell' } } cb() }, onReport: function (s) { var cols = [] if (typeof s.sar === 'number') { cols.push(z(8, n(s.sar).subtract(s.period.close).divide(s.period.close).format('0.00%'), ' ').grey) } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(2, 100), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy sar_af: Phenotypes.RangeFloat(0.01, 1.0), sar_max_af: Phenotypes.RangeFloat(0.01, 1.0) } } ================================================ FILE: extensions/strategies/speed/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'speed', description: 'Trade when % change from last two 1m periods is higher than average.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1m') this.option('period_length', 'period length, same as --period', String, '1m') this.option('min_periods', 'min. number of history periods', Number, 3000) this.option('baseline_periods', 'lookback periods for volatility baseline', Number, 3000) this.option('trigger_factor', 'multiply with volatility baseline EMA to get trigger value', Number, 1.6) }, calculate: function (s) { if (s.lookback[1]) { s.period.speed = (s.period.close - s.lookback[1].close) / s.lookback[1].close * 100 s.period.abs_speed = Math.abs((s.period.close - s.lookback[1].close) / s.lookback[1].close * 100) if (s.lookback[s.options.baseline_periods + 1]) { ema(s, 'baseline', s.options.baseline_periods, 'abs_speed') } } }, onPeriod: function (s, cb) { if (typeof s.period.baseline === 'number') { if (s.period.speed >= s.period.baseline * s.options.trigger_factor) { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null } else if (s.period.speed <= s.period.baseline * s.options.trigger_factor * -1) { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } } cb() }, onReport: function (s) { var cols = [] cols.push(z(8, n(s.period.speed).format('0.0000'), ' ')[s.period.speed >= 0 ? 'green' : 'red']) if (typeof s.period.baseline === 'number') { cols.push(z(8, n(s.period.baseline).format('0.0000'), ' ').grey) } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 100), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy baseline_periods: Phenotypes.Range(1, 5000), trigger_factor: Phenotypes.RangeFloat(0.1, 10) } } ================================================ FILE: extensions/strategies/srsi_macd/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , srsi = require('../../../lib/srsi') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'srsi_macd', description: 'Stochastic MACD Strategy', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') this.option('min_periods', 'min. number of history periods', Number, 200) this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('srsi_periods', 'number of RSI periods', Number, 9) this.option('srsi_k', '%D line', Number, 5) this.option('srsi_d', '%D line', Number, 3) this.option('oversold_rsi', 'buy when RSI reaches or drops below this value', Number, 20) this.option('overbought_rsi', 'sell when RSI reaches or goes above this value', Number, 80) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 24) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 200) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) }, calculate: function (s) { // compute Stochastic RSI srsi(s, 'srsi', s.options.rsi_periods, s.options.srsi_k, s.options.srsi_d) // compute MACD ema(s, 'ema_short', s.options.ema_short_period) ema(s, 'ema_long', s.options.ema_long_period) if (s.period.ema_short && s.period.ema_long) { s.period.macd = (s.period.ema_short - s.period.ema_long) ema(s, 'signal', s.options.signal_period, 'macd') if (s.period.signal) { s.period.macd_histogram = s.period.macd - s.period.signal } } }, onPeriod: function (s, cb) { if (!s.in_preroll) if (typeof s.period.macd_histogram === 'number' && typeof s.lookback[0].macd_histogram === 'number' && typeof s.period.srsi_K === 'number' && typeof s.period.srsi_D === 'number') // Buy signal if (s.period.macd_histogram >= s.options.up_trend_threshold) if (s.period.srsi_K > s.period.srsi_D && s.period.srsi_K > s.lookback[0].srsi_K && s.period.srsi_K < s.options.oversold_rsi) s.signal = 'buy' // Sell signal if (s.period.macd_histogram < s.options.down_trend_threshold) if (s.period.srsi_K < s.period.srsi_D && s.period.srsi_K < s.lookback[0].srsi_K && s.period.srsi_K > s.options.overbought_rsi) s.signal = 'sell' // Hold //s.signal = null; cb() }, onReport: function (s) { var cols = [] if (typeof s.period.macd_histogram === 'number') { var color = 'grey' if (s.period.macd_histogram > 0) { color = 'green' } else if (s.period.macd_histogram < 0) { color = 'red' } cols.push(z(8, n(s.period.macd_histogram).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.srsi_K).format('00.00'), ' ').cyan) cols.push(z(8, n(s.period.srsi_D).format('00.00'), ' ').yellow) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy rsi_periods: Phenotypes.Range(1, 200), srsi_periods: Phenotypes.Range(1, 200), srsi_k: Phenotypes.Range(1, 50), srsi_d: Phenotypes.Range(1, 50), oversold_rsi: Phenotypes.Range(1, 100), overbought_rsi: Phenotypes.Range(1, 100), ema_short_period: Phenotypes.Range(1, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), up_trend_threshold: Phenotypes.Range(0, 20), down_trend_threshold: Phenotypes.Range(0, 20) } } ================================================ FILE: extensions/strategies/stddev/strategy.js ================================================ var z = require('zero-fill') , stats = require('stats-lite') , math = require('mathjs') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'stddev', description: 'Buy when standard deviation and mean increase, sell on mean decrease.', getOptions: function () { this.option('period', 'period length, set poll trades to 100ms, poll order 1000ms. Same as --period_length', String, '100ms') this.option('period_length', 'period length, set poll trades to 100ms, poll order 1000ms. Same as --period', String, '100ms') this.option('trendtrades_1', 'Trades for array 1 to be subtracted stddev and mean from', Number, 5) this.option('trendtrades_2', 'Trades for array 2 to be calculated stddev and mean from', Number, 53) this.option('min_periods', 'min_periods', Number, 1250) }, calculate: function () { }, onPeriod: function (s, cb) { ema(s, 'stddev', s.options.stddev) var tl0 = [] var tl1 = [] if (s.lookback[s.options.min_periods]) { for (let i = 0; i < s.options.trendtrades_1; i++) { tl0.push(s.lookback[i].close) } for (let i = 0; i < s.options.trendtrades_2; i++) { tl1.push(s.lookback[i].close) } s.std0 = stats.stdev(tl0) / 2 s.std1 = stats.stdev(tl1) / 2 s.mean0 = math.mean(tl0) s.mean1 = math.mean(tl1) s.sig0 = s.std0 > s.std1 ? 'Up' : 'Down' s.sig1 = s.mean0 > s.mean1 ? 'Up' : 'Down' } if (s.sig1 === 'Down') { s.signal = 'sell' } else if (s.sig0 === 'Up' && s.sig1 === 'Up') { s.signal = 'buy' } cb() }, onReport: function (s) { var cols = [] cols.push(z(s.signal, ' ')[s.signal === false ? 'red' : 'green']) return cols }, phenotypes: { // -- common // reference in extensions is given in ms have not heard of an exchange that supports 500ms thru api so setting min at 1 second period_length: Phenotypes.RangePeriod(1, 7200, 's'), min_periods: Phenotypes.Range(1, 2500), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy trendtrades_1: Phenotypes.Range(2, 20), trendtrades_2: Phenotypes.Range(4, 100) } } ================================================ FILE: extensions/strategies/ta_ema/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , ta_ema = require('../../../lib/ta_ema') , rsi = require('../../../lib/rsi') , stddev = require('../../../lib/stddev') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_ema', description: 'Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '10m') this.option('period_length', 'period length, same as --period', String, '10m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('trend_ema', 'number of periods for trend EMA', Number, 20) this.option('neutral_rate', 'avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter)', Number, 0.06) this.option('oversold_rsi_periods', 'number of periods for oversold RSI', Number, 20) this.option('oversold_rsi', 'buy when RSI reaches this value', Number, 30) }, calculate: function (s) { if (s.options.oversold_rsi) { // sync RSI display with oversold RSI periods s.options.rsi_periods = s.options.oversold_rsi_periods rsi(s, 'oversold_rsi', s.options.oversold_rsi_periods) if (!s.in_preroll && s.period.oversold_rsi <= s.options.oversold_rsi && !s.oversold && !s.cancel_down) { s.oversold = true if (s.options.mode !== 'sim' || s.options.verbose) console.log(('\noversold at ' + s.period.oversold_rsi + ' RSI, preparing to buy\n').cyan) } } if (s.options.neutral_rate === 'auto') { stddev(s, 'trend_ema_stddev', Math.floor(s.options.trend_ema / 2), 'trend_ema_rate') } else { s.period.trend_ema_stddev = s.options.neutral_rate } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.oversold_rsi === 'number') { if (s.oversold) { s.oversold = false s.trend = 'oversold' s.signal = 'buy' s.cancel_down = true return cb() } } // wait for promise to be resolved // we add all maybe we need more indicators Promise.all([ta_ema(s, s.options.trend_ema)]).then(result => { if(result && result.outReal) { s.period.trend_ema = result.outReal } }) // calculate ema rate if (s.period.trend_ema && s.lookback[0] && s.lookback[0].trend_ema) { s.period.trend_ema_rate = (s.period.trend_ema - s.lookback[0].trend_ema) / s.lookback[0].trend_ema * 100 } if (typeof s.period.trend_ema_stddev === 'number') { if (s.period.trend_ema_rate > s.period.trend_ema_stddev) { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null s.cancel_down = false } else if (!s.cancel_down && s.period.trend_ema_rate < (s.period.trend_ema_stddev * -1)) { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } } cb() }, onReport: function (s) { var cols = [] if (typeof s.period.trend_ema_stddev === 'number') { var color = 'grey' if (s.period.trend_ema_rate > s.period.trend_ema_stddev) { color = 'green' } else if (s.period.trend_ema_rate < (s.period.trend_ema_stddev * -1)) { color = 'red' } cols.push(z(8, n(s.period.trend_ema_rate).format('0.0000'), ' ')[color]) if (s.period.trend_ema_stddev) { cols.push(z(8, n(s.period.trend_ema_stddev).format('0.0000'), ' ').grey) } } else { if (s.period.trend_ema_stddev) { cols.push(' ') } else { cols.push(' ') } } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 100), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy trend_ema: Phenotypes.Range(1, 40), oversold_rsi_periods: Phenotypes.Range(5, 50), oversold_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ta_macd/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ta_macd = require('../../../lib/ta_macd') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_macd', description: 'Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 12) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 26) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.trend = 'overbought' s.signal = 'sold' return cb() } } ta_macd(s, s.options.ema_long_period, s.options.ema_short_period, s.options.signal_period).then(function(signal) { if(!signal) { cb() return } s.period['macd'] = signal.macd s.period['macd_histogram'] = signal.macd_histogram s.period['macd_signal'] = signal.macd_signal if (typeof s.period.macd_histogram === 'number' && typeof s.lookback[0].macd_histogram === 'number') { if ((s.period.macd_histogram - s.options.up_trend_threshold) > 0 && (s.lookback[0].macd_histogram - s.options.up_trend_threshold) <= 0) { s.signal = 'buy' } else if ((s.period.macd_histogram + s.options.down_trend_threshold) < 0 && (s.lookback[0].macd_histogram + s.options.down_trend_threshold) >= 0) { s.signal = 'sell' } else { s.signal = null // hold } } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { var cols = [] if (typeof s.period.macd_histogram === 'number') { var color = 'grey' if (s.period.macd_histogram > 0) { color = 'green' } else if (s.period.macd_histogram < 0) { color = 'red' } cols.push(z(8, n(s.period.macd_histogram).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.overbought_rsi).format('00'), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy // have to be minimum 2 because talib will throw an "TA_BAD_PARAM" error ema_short_period: Phenotypes.Range(2, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), up_trend_threshold: Phenotypes.Range(0, 50), down_trend_threshold: Phenotypes.Range(0, 50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ta_macd_ext/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ta_macd_ext = require('../../../lib/ta_macd_ext') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_macd_ext', description: 'Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0) with controllable talib TA types', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 12) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 26) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('fast_ma_type', 'fast_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3', String, null) this.option('slow_ma_type', 'slow_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3', String, null) this.option('signal_ma_type', 'signal_ma_type of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3', String, null) this.option('default_ma_type', 'set default ma_type for fast, slow and signal. You are able to overwrite single types separately (fast_ma_type, slow_ma_type, signal_ma_type)', String, 'SMA') this.option('up_trend_threshold', 'threshold to trigger a buy signal', Number, 0) this.option('down_trend_threshold', 'threshold to trigger a sold signal', Number, 0) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) { console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.signal = 'sell' return cb() } } let types = { 'fast_ma_type': s.options.default_ma_type || 'SMA', 'slow_ma_type': s.options.default_ma_type || 'SMA', 'signal_ma_type': s.options.default_ma_type || 'SMA', } if (s.options.fast_ma_type) { types['fast_ma_type'] = s.options.fast_ma_type } if (s.options.slow_ma_type) { types['slow_ma_type'] = s.options.slow_ma_type } if (s.options.signal_ma_type) { types['signal_ma_type'] = s.options.signal_ma_type } ta_macd_ext( s, s.options.ema_long_period, s.options.ema_short_period, s.options.signal_period, types['fast_ma_type'], types['slow_ma_type'], types['signal_ma_type'] ).then(function(signal) { if(!signal) { cb() return } s.period['macd'] = signal.macd s.period['macd_histogram'] = signal.macd_histogram s.period['macd_signal'] = signal.macd_signal if (typeof s.period.macd_histogram === 'number' && typeof s.lookback[0].macd_histogram === 'number') { if ((s.period.macd_histogram - s.options.up_trend_threshold) > 0 && (s.lookback[0].macd_histogram - s.options.up_trend_threshold) <= 0) { s.signal = 'buy' } else if ((s.period.macd_histogram + s.options.down_trend_threshold) < 0 && (s.lookback[0].macd_histogram + s.options.down_trend_threshold) >= 0) { s.signal = 'sell' } else { s.signal = null // hold } } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { var cols = [] if (typeof s.period.macd_histogram === 'number') { var color = 'grey' if (s.period.macd_histogram > 0) { color = 'green' } else if (s.period.macd_histogram < 0) { color = 'red' } cols.push(z(8, n(s.period.macd_histogram).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.overbought_rsi).format('00'), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 104), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // have to be minimum 2 because talib will throw an "TA_BAD_PARAM" error ema_short_period: Phenotypes.Range(2, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), fast_ma_type: Phenotypes.RangeMaType(), slow_ma_type: Phenotypes.RangeMaType(), signal_ma_type: Phenotypes.RangeMaType(), default_ma_type: Phenotypes.RangeMaType(), // this.option('default_ma_type', 'set default ma_type for fast, slow and signal. You are able to overwrite single types separately (fast_ma_type, slow_ma_type, signal_ma_type)', String, 'SMA') up_trend_threshold: Phenotypes.Range(0, 50), down_trend_threshold: Phenotypes.Range(0, 50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ta_ppo/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ta_ppo = require('../../../lib/ta_ppo') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_ppo', description: 'PPO - Percentage Price Oscillator with rsi oversold', getOptions: function () { this.option('period', 'period length eg 10m', String, '10m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('ema_short_period', 'number of periods for the shorter EMA', Number, 12) this.option('ema_long_period', 'number of periods for the longer EMA', Number, 26) this.option('signal_period', 'number of periods for the signal EMA', Number, 9) this.option('ma_type', 'matype of talib: SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3', String, 'SMA') this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) { console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.signal = 'sell' return cb() } } ta_ppo(s, s.options.ema_long_period, s.options.ema_short_period, s.options.signal_period, s.options.ma_type).then(function(ppoSignal) { s.period['ppo'] = ppoSignal if (s.period.ppo && s.lookback[0] && s.lookback[0].ppo) { s.period.trend_ppo = s.period.ppo >= 0 ? 'up' : 'down' } if (s.period.trend_ppo == 'up') { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null } else if (s.period.trend_ppo == 'down') { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { let cols = [] if (typeof s.period.ppo === 'number') { let color = s.period.ppo > 0 ? 'green' : 'red' cols.push(z(8, n(s.period.ppo).format('0.0000'), ' ')[color]) } return cols }, phenotypes: { period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 104), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // have to be minimum 2 because talib will throw an "TA_BAD_PARAM" error ema_short_period: Phenotypes.Range(2, 20), ema_long_period: Phenotypes.Range(20, 100), signal_period: Phenotypes.Range(1, 20), ma_type: Phenotypes.RangeMaType(), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ta_srsi_bollinger/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , ta_srsi = require('../../../lib/ta_stochrsi') , ta_bollinger = require('../../../lib/ta_bollinger') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'srsi_bollinger', description: 'Stochastic RSI BollingerBand Strategy', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '5m') this.option('period_length', 'period length, same as --period', String, '5m') this.option('min_periods', 'min. number of history periods', Number, 200) this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('srsi_periods', 'number of Stochastic RSI periods',Number, 9) this.option('srsi_k', '%D line', Number, 3) this.option('srsi_d', '%D line', Number, 3) this.option('srsi_k_sell', 'K must be above this before selling', Number, 60) this.option('srsi_k_buy', 'K must be below this before buying', Number, 30) this.option('srsi_dType','D type mode : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA'), //'SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3' this.option('bollinger_size', 'period size', Number, 14) this.option('bollinger_updev', 'Upper Bollinger Time Divisor', Number, 2) this.option('bollinger_dndev', 'Lower Bollinger Time Divisor', Number, 2) this.option('bollinger_dType','mode: : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA') this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 1) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 1) }, calculate: function (s) { if (s.in_preroll) return }, onPeriod: function (s, cb) { //make sure we have all values if (s.in_preroll) return cb() ta_bollinger(s,'tabollinger',s.options.bollinger_size, s.options.bollinger_updev, s.options.bollinger_dndev, s.options.bollinger_dType). then(function(inbol){ ta_srsi(s, 'srsi', s.options.srsi_periods, s.options.srsi_k, s.options.srsi_d, s.options.srsi_dType). then(function(inres) { if (!inres) return cb() var divergent = inres.outFastK[inres.outFastK.length-1] - inres.outFastD[inres.outFastD.length-1] s.period.srsi_D = inres.outFastD[inres.outFastD.length-1] s.period.srsi_K = inres.outFastK[inres.outFastK.length-1] var last_divergent = inres.outFastK[inres.outFastK.length-2] - inres.outFastD[inres.outFastD.length-2] var _switch = 0//s.lookback[0]._switch var nextdivergent = (( divergent + last_divergent ) /2) + (divergent - last_divergent) if ((last_divergent <= 0 && (divergent > 0)) ) _switch = 1 // price rising if ((last_divergent >= 0 && (divergent < 0)) ) _switch = -1 // price falling s.period.divergent = divergent s.period._switch = _switch let upperBound = inbol.outRealUpperBand[inbol.outRealUpperBand.length-1] let lowerBound = inbol.outRealLowerBand[inbol.outRealLowerBand.length-1] let midBound =inbol.outRealMiddleBand[inbol.outRealMiddleBand.length-1] if (!s.period.bollinger) s.period.bollinger = {} s.period.bollinger.upperBound = upperBound s.period.bollinger.lowerBound = lowerBound s.period.bollinger.midBound = midBound // K is fast moving s.signal = null if (_switch != 0 ) { if (s.period.close > ((upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) && nextdivergent < divergent && _switch == -1 && s.period.srsi_K > s.options.srsi_k_sell) { s.signal = 'sell' } else if (s.period.close < ((lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) && nextdivergent >= divergent && _switch == 1 && s.period.srsi_K < s.options.srsi_k_buy) { s.signal = 'buy' } } cb() }).catch(function(){ cb()}) }).catch(function(){ cb()}) }, onReport: function (s) { var cols = [] if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound var color = 'grey' if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { color = 'green' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.srsi_D).format('0.0000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.srsi_K).format('0.0000').substring(0,7), ' ').cyan) cols.push(z(5, n(s.period.divergent).format('0').substring(0,7), ' ').cyan) cols.push(z(2, n(s.period._switch).format('0').substring(0,2), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.ListOption(['1m', '2m', '3m', '4m', '5m', '10m','15m']),//, '10m','15m','30m','45m','60m' min_periods: Phenotypes.Range(52, 150), markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), markup_sell_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0, 0.1), profit_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), // -- strategy rsi_periods: Phenotypes.Range(10, 20), srsi_periods: Phenotypes.Range(5, 30), srsi_k: Phenotypes.Range(1, 30), srsi_d: Phenotypes.Range(1, 30), srsi_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), srsi_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), srsi_dType: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), bollinger_size: Phenotypes.RangeFactor(10, 25, 1), bollinger_updev: Phenotypes.RangeFactor(1, 3.0, 0.1), bollinger_dndev: Phenotypes.RangeFactor(1, 3.0, 0.1), bollinger_dType: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0), bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0) } } ================================================ FILE: extensions/strategies/ta_stoch_bollinger/strategy.js ================================================ let z = require('zero-fill'), n = require('numbro'), ta_stoch = require('../../../lib/ta_stoch'), ta_bollinger = require('../../../lib/ta_bollinger'), Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_stoch_bollinger', description: 'Stochastic BollingerBand Strategy', getOptions: function() { this.option('period', 'period length, same as --period_length', String, '3m') this.option('period_length', 'period length, same as --period', String, '3m') this.option('min_periods', 'min. number of history periods', Number, 200) // this.option('rsi_periods', 'Time period for building the Fast-K line', Number, 14) this.option('stoch_periods', 'Time period for building the Fast-K line', Number, 14) this.option('stoch_k', 'Smoothing for making the Slow-K line. Usually set to 3', Number, 3) this.option('stoch_k_ma_type', 'Type of Moving Average for Slow-K : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'DEMA'), this.option('stoch_d', 'Smoothing for making the Slow-D line', Number, 3) this.option('stoch_d_ma_type', 'Type of Moving Average for Slow-D : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'DEMA'), this.option('stoch_k_sell', 'K must be above this before selling', Number, 75) this.option('stoch_k_buy', 'K must be below this before buying', Number, 25) this.option('bollinger_size', 'period size', Number, 20) this.option('bollinger_updev', '', Number, 2) this.option('bollinger_dndev', '', Number, 2) this.option('bollinger_dType', 'mode: : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA') this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 0) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) }, calculate: function(s) { if (s.in_preroll) return }, onPeriod: function(s, cb) { //make sure we have all values if (s.in_preroll) return cb() ta_bollinger(s, 'tabollinger', s.options.bollinger_size, s.options.bollinger_updev, s.options.bollinger_dndev, s.options.bollinger_dType) .then(function(inbol) { ta_stoch(s, 'stoch', s.options.stoch_periods, s.options.stoch_k, s.options.stoch_k_ma_type, s.options.stoch_d, s.options.stoch_d_ma_type) .then(function(inres) { if (!inres) return cb() var divergent = inres.k[inres.k.length - 1] - inres.d[inres.k.length - 1] s.period.stoch_D = inres.d[inres.d.length - 1] s.period.stoch_K = inres.k[inres.k.length - 1] var last_divergent = inres.k[inres.k.length - 2] - inres.d[inres.d.length - 2] var _switch = 0 var nextdivergent = ((divergent + last_divergent) / 2) + (divergent - last_divergent) if (last_divergent <= 0 && divergent > 0) { _switch = 1 // price rising } if (last_divergent >= 0 && divergent < 0) { _switch = -1 // price falling } s.period.divergent = divergent s.period._switch = _switch let upperBound = inbol.outRealUpperBand[inbol.outRealUpperBand.length - 1] let lowerBound = inbol.outRealLowerBand[inbol.outRealLowerBand.length - 1] let midBound = inbol.outRealMiddleBand[inbol.outRealMiddleBand.length - 1] if (!s.period.bollinger) { s.period.bollinger = {} } s.period.bollinger.upperBound = upperBound s.period.bollinger.lowerBound = lowerBound s.period.bollinger.midBound = midBound // K is fast moving s.signal = null if (_switch != 0) { if (s.period.close >= midBound && Math.max(s.period.close, s.period.open) >= (upperBound / 100) * (100 + s.options.bollinger_upper_bound_pct) && nextdivergent < divergent && _switch == -1 && s.period.stoch_K > s.options.stoch_k_sell) { s.signal = 'sell' } else if (Math.min(s.period.close, s.period.open) <= (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct) && nextdivergent > divergent && _switch == 1 && s.period.stoch_K < s.options.stoch_k_buy) { s.signal = 'buy' } } cb() }).catch(function() { cb() }) }).catch(function() { cb() }) }, onReport: function(s) { var cols = [] if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound var color = 'grey' if (Math.max(s.period.close, s.period.open) > (upperBound / 100) * (100 + s.options.bollinger_upper_bound_pct)) { color = 'green' } if (Math.min(s.period.close, s.period.open) < (lowerBound / 100) * (100 - s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.0000').substring(0, 7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.0000').substring(0, 7), ' ').cyan) cols.push(z(8, n(s.period.stoch_D).format('0.0000').substring(0, 7), ' ').cyan) cols.push(z(8, n(s.period.stoch_K).format('0.0000').substring(0, 7), ' ').cyan) cols.push(z(5, n(s.period.divergent).format('0').substring(0, 7), ' ').cyan) cols.push(z(2, n(s.period._switch).format('0').substring(0, 2), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.ListOption(['1m', '2m', '3m', '4m', '5m', '10m', '15m']), min_periods: Phenotypes.Range(52, 150), markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), markup_sell_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0, 0.1), profit_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), // -- strategy // rsi_periods: Phenotypes.Range(10, 30), stoch_periods: Phenotypes.Range(5, 30), stoch_k: Phenotypes.Range(1, 10), stoch_k_ma_type: Phenotypes.ListOption(['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA', 'KAMA', 'MAMA', 'T3']), stoch_d: Phenotypes.Range(1, 10), stoch_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), stoch_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), stoch_d_ma_type: Phenotypes.ListOption(['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA', 'KAMA', 'MAMA', 'T3']), bollinger_size: Phenotypes.RangeFactor(10, 25, 1), bollinger_updev: Phenotypes.RangeFactor(1, 3.0, 0.1), bollinger_dndev: Phenotypes.RangeFactor(1, 3.0, 0.1), bollinger_dType: Phenotypes.ListOption(['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA', 'KAMA', 'MAMA', 'T3']), bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0), bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0) } } ================================================ FILE: extensions/strategies/ta_trix/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ta_trix = require('../../../lib/ta_trix') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_trix', description: 'TRIX - 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA with rsi oversold', getOptions: function () { this.option('period', 'period length eg 10m', String, '5m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('timeperiod', 'timeperiod for TRIX', Number, 30) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) { console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.signal = 'sell' return cb() } } ta_trix(s, s.options.timeperiod).then(function(signal) { s.period['trix'] = signal if (s.period.trix && s.lookback[0] && s.lookback[0].trix) { s.period.trend_trix = s.period.trix >= 0 ? 'up' : 'down' } if (s.period.trend_trix == 'up') { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null } else if (s.period.trend_trix == 'down') { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { let cols = [] if (typeof s.period.trix === 'number') { let color = s.period.trix > 0 ? 'green' : 'red' cols.push(z(8, n(s.period.trix).format('0.0000'), ' ')[color]) } return cols }, phenotypes: { period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 104), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), timeperiod: Phenotypes.Range(1,60), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ta_ultosc/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ultosc = require('../../../lib/ta_ultosc') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ta_ultosc', description: 'ULTOSC - Ultimate Oscillator with rsi oversold', getOptions: function () { this.option('period', 'period length eg 5m', String, '5m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('signal', 'Provide signal and indicator "simple" (buy@65, sell@50), "low" (buy@65, sell@30), "trend" (buy@30, sell@70)', String, 'simple') this.option('timeperiod1', 'talib ULTOSC timeperiod1', Number, 7) this.option('timeperiod2', 'talib ULTOSC timeperiod2', Number, 14) this.option('timeperiod3', 'talib ULTOSC timeperiod3', Number, 28) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 90) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) { console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.signal = 'sell' return cb() } } ultosc(s, s.options.min_periods, s.options.timeperiod1, s.options.timeperiod2, s.options.timeperiod3).then(function(signal) { s.period['ultosc'] = signal let t = s.signales || {} var signals = { bottom: t.bottom || 0, // 30 line top: t.top || 0, // 70 line } if (s.period.ultosc && s.period.ultosc > 0) { if (s.options.signal == 'simple') { // use defensive indicator trigger if (s.period.ultosc > 65) { s.period.trend_ultosc = 'up' } else if (s.period.ultosc < 50) { s.period.trend_ultosc = 'down' } } else if (s.options.signal == 'low') { // use recovery indicator trigger if(s.period.ultosc > 65) { s.period.trend_ultosc = 'up' } else if(s.period.ultosc < 30 && signals.bottom == 0) { s.period.trend_ultosc = 'down' } } else if (s.options.signal == 'trend') { // lets got with the masses if(s.period.ultosc > 30 && signals.bottom > 0) { s.period.trend_ultosc = 'up' } else if(s.period.ultosc < 70 && signals.top > 0) { s.period.trend_ultosc = 'down' } } signals.bottom = s.period.ultosc < 30 ? signals.bottom + 1 : 0 signals.top = s.period.ultosc > 70 ? signals.top + 1 : 0 s.signales = signals } if (s.period.trend_ultosc == 'up') { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null } else if (s.period.trend_ultosc == 'down') { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { let cols = [] if (typeof s.period.ultosc === 'number') { let signal = z(8, n(s.period.ultosc).format('0.0000'), ' ') if (s.period.ultosc <= 30) { cols.push(signal.red) } else if (s.period.ultosc > 30 && s.period.ultosc <= 50) { cols.push(signal.yellow) } else if (s.period.ultosc > 50 && s.period.ultosc < 70) { cols.push(signal.green) } else if (s.period.ultosc >= 70) { cols.push(signal.bold.green) } } return cols }, phenotypes: { period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 104), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), signal: Phenotypes.ListOption(['simple', 'low', 'trend']), timeperiod1: Phenotypes.Range(1,50), timeperiod2: Phenotypes.Range(1,50), timeperiod3: Phenotypes.Range(1,50), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ti_bollinger/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , tulip_bollinger = require('../../../lib/ti_bollinger') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ti_bollinger', description: 'Buy when (Signal ≤ Lower Bollinger Band) and sell when (Signal ≥ Upper Bollinger Band).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '5m') this.option('period_length', 'period length, same as --period', String, '5m') this.option('bollinger_size', 'period size', Number, 14) this.option('bollinger_time', 'times of standard deviation between the upper band and the moving averages', Number, 2) this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 0) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) }, calculate: function (s) { if (s.in_preroll) return }, onPeriod: function (s, cb) { tulip_bollinger(s,'tulip_bollinger', s.options.bollinger_size, s.options.bollinger_time). then(function(result) { if (!result) cb() let bollinger = { LowerBand: result.LowerBand[result.LowerBand.length-1], MiddleBand: result.MiddleBand[result.MiddleBand.length-1], UpperBand: result.UpperBand[result.UpperBand.length-1] } s.period.report = bollinger if (bollinger.UpperBand) { let upperBound = (bollinger.UpperBand / 100) * (100 - s.options.bollinger_upper_bound_pct) let lowerBound = (bollinger.LowerBand / 100) * (100 + s.options.bollinger_lower_bound_pct) s.signal = null // hold if (s.period.close < lowerBound ) { s.signal = 'buy' } if (s.period.close > upperBound ) { s.signal = 'sell' } } cb() }).catch(function(){ s.signal = null // hold cb() }) }, onReport: function (s) { var cols = [] if (s.period.report) { if (s.period.report.UpperBand && s.period.report.LowerBand) { let upperBound = s.period.report.UpperBand let lowerBound = s.period.report.LowerBand var color = 'grey' if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { color = 'green' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 5.0, 0.1), markup_sell_pct: Phenotypes.RangeFactor(-1.0, 5.0, 0.1), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.01), buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.01), profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0,0.1), profit_stop_pct: Phenotypes.RangeFactor(0.0, 20.0,0.1), rsi_periods: Phenotypes.Range(6, 16), // -- strategy bollinger_size: Phenotypes.RangeFactor(1, 30, 1), bollinger_time: Phenotypes.RangeFactor(1.0, 14.0, 0.1), bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 0.1), bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 0.1) } } ================================================ FILE: extensions/strategies/ti_hma/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , rsi = require('../../../lib/rsi') , ti_hma = require('../../../lib/ti_hma') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ti_hma', description: 'HMA - Hull Moving Average', getOptions: function () { this.option('period', 'period length eg 10m', String, '15m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('trend_hma', 'number of periods for trend hma', Number, 36) this.option('overbought_rsi_periods', 'number of periods for overbought RSI', Number, 25) this.option('overbought_rsi', 'sold when RSI exceeds this value', Number, 70) }, calculate: function (s) { if (s.options.overbought_rsi) { // sync RSI display with overbought RSI periods s.options.rsi_periods = s.options.overbought_rsi_periods rsi(s, 'overbought_rsi', s.options.overbought_rsi_periods) if (!s.in_preroll && s.period.overbought_rsi >= s.options.overbought_rsi && !s.overbought) { s.overbought = true if (s.options.mode === 'sim' && s.options.verbose) { console.log(('\noverbought at ' + s.period.overbought_rsi + ' RSI, preparing to sold\n').cyan) } } } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.overbought_rsi === 'number') { if (s.overbought) { s.overbought = false s.signal = 'sell' return cb() } } ti_hma(s, s.options.min_periods, s.options.trend_hma).then(function(signal) { s.period['trend_hma'] = signal // percentage change if (s.period.trend_hma && s.lookback[0] && s.lookback[0].trend_hma) { s.period.trend_hma_rate = (s.period.trend_hma - s.lookback[0].trend_hma) / s.lookback[0].trend_hma * 100 } if (s.period.trend_hma_rate > 0) { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null s.cancel_down = false } else if (!s.cancel_down && s.period.trend_hma_rate < 0) { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } cb() }).catch(function(error) { console.log(error) cb() }) }, onReport: function (s) { var cols = [] if (typeof s.period.trend_hma === 'number') { var color = 'grey' if (s.period.trend_hma_rate > 0) { color = 'green' } else if (s.period.trend_hma_rate < 0) { color = 'red' } cols.push(z(8, n(s.period.trend_hma).format('0.0000'), ' ')[color]) cols.push(z(6, n(s.period.trend_hma_rate).format('0.00'), ' ')[color]) } return cols }, phenotypes: { period_length: Phenotypes.RangePeriod(5, 120, 'm'), min_periods: Phenotypes.Range(20, 104), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), trend_hma: Phenotypes.Range(6, 72), overbought_rsi_periods: Phenotypes.Range(1, 50), overbought_rsi: Phenotypes.Range(20, 100) } } ================================================ FILE: extensions/strategies/ti_stoch/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , tulip_stoch = require('../../../lib/ti_stoch') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ti_stoch', description: 'Buy when (Signal ≤ srsi_k_buy) and sell when (Signal ≥ srsi_k_sell). (this should not be used alone. you will lose over time)', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '5m') this.option('period_length', 'period length, same as --period', String, '5m') this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('stoch_kperiods', 'number of RSI periods', Number, 9) this.option('stoch_k', '%D line', Number, 3) this.option('stoch_d', '%D line', Number, 3) this.option('stoch_k_sell', 'K must be above this before selling', Number, 80) this.option('stoch_k_buy', 'K must be below this before buying', Number, 10) }, calculate: function (s) { if (s.in_preroll) return }, onPeriod: function (s, cb) { if (s.in_preroll) return cb() tulip_stoch(s,'tulip_stoch', s.options.rsi_periods, s.options.stoch_k, s.options.stoch_d). then(function(result) { if (!result) return cb() if (result.k.length == 0) return cb() var divergent = result.k[result.k.length-1] - result.d[result.d.length-1] s.period.srsi_D = result.d[result.d.length-1] s.period.srsi_K = result.k[result.k.length-1] var last_divergent = result.k[result.k.length-2] - result.d[result.d.length-2] var _switch = 0//s.lookback[0]._switch var nextdivergent = (( divergent + last_divergent ) /2) + (divergent - last_divergent) if ((last_divergent <= 0 && (divergent > 0)) ) _switch = 1 // price rising if ((last_divergent >= 0 && (divergent < 0)) ) _switch = -1 // price falling s.period.divergent = divergent s.period._switch = _switch s.signal = null if (_switch != 0 ) { if (_switch == -1 && s.period.srsi_K > s.options.stoch_k_sell) { s.signal = 'sell' } else if ( nextdivergent >= divergent && _switch == 1 && s.period.srsi_K < s.options.stoch_k_buy) { s.signal = 'buy' } } return cb() }).catch(function(){ s.signal = null // hold return cb() }) }, onReport: function (s) { var cols = [] cols.push(z(8, n(s.period.close).format('+00.0000'), ' ').cyan) cols.push(z(8, n( s.period.srsi_D).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.srsi_K).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.divergent).format('0').substring(0,3), ' ').cyan) cols.push(z(8, n( s.period._switch ).format('0').substring(0,2), ' ').cyan) return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 5.0, 0.1), markup_sell_pct: Phenotypes.RangeFactor(-1.0, 5.0, 0.1), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.01), buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.01), profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0,0.1), profit_stop_pct: Phenotypes.RangeFactor(0.0, 20.0,0.1), // -- strategy rsi_periods: Phenotypes.Range(10, 30), stoch_periods: Phenotypes.Range(5, 30), stoch_k: Phenotypes.Range(1, 10), stoch_d: Phenotypes.Range(1, 10), stoch_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), stoch_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), } } ================================================ FILE: extensions/strategies/ti_stoch_bollinger/strategy.js ================================================ let z = require('zero-fill') , n = require('numbro') , ti_stoch = require('../../../lib/ti_stoch') , ti_bollinger = require('../../../lib/ti_bollinger') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'ti_stoch_bollinger', description: 'Stochastic BollingerBand Strategy', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '5m') this.option('period_length', 'period length, same as --period', String, '5m') this.option('min_periods', 'min. number of history periods', Number, 200) this.option('rsi_periods', 'number of RSI periods', Number, 14) this.option('stoch_kperiods', 'number of RSI periods', Number, 9) this.option('stoch_k', '%D line', Number, 5) this.option('stoch_d', '%D line', Number, 3) this.option('stoch_k_sell', 'K must be above this before selling', Number, 70) this.option('stoch_k_buy', 'K must be below this before buying', Number, 20) this.option('bollinger_size', 'period size', Number, 14) this.option('bollinger_time', 'times of standard deviation between the upper band and the moving averages', Number, 2) this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 0) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) }, calculate: function (s) { if (s.in_preroll) return }, onPeriod: function (s, cb) { //make sure we have all values if (s.in_preroll) return cb() ti_bollinger(s,'ti_bollinger', s.options.bollinger_size, s.options.bollinger_time). then(function(inbol){ ti_stoch(s,'ti_stoch', s.options.stoch_kperiods, s.options.stoch_k, s.options.stoch_d). then(function(inres) { if (!inres) return cb() if (inres.k.length == 0) return cb() var divergent = inres.k[inres.k.length-1] - inres.d[inres.d.length-1] s.period.stoch_D = inres.d[inres.d.length-1] s.period.stoch_K = inres.k[inres.k.length-1] var last_divergent = inres.k[inres.k.length-2] - inres.d[inres.d.length-2] var _switch = 0 var nextdivergent = (( divergent + last_divergent ) /2) + (divergent - last_divergent) if ((last_divergent <= 0 && (divergent > 0)) ) _switch = 1 // price rising if ((last_divergent >= 0 && (divergent < 0)) ) _switch = -1 // price falling s.period.divergent = divergent s.period._switch = _switch let LowerBand= inbol.LowerBand[inbol.LowerBand.length-1] let MiddleBand= inbol.MiddleBand[inbol.MiddleBand.length-1] let UpperBand= inbol.UpperBand[inbol.UpperBand.length-1] let bollinger = { LowerBand: LowerBand, MiddleBand: MiddleBand, UpperBand: UpperBand } s.period.report = bollinger // K is fast moving s.signal = null if (_switch != 0 ) { if (s.period.close >= MiddleBand && s.period.close >= ((UpperBand / 100) * (100 + s.options.bollinger_upper_bound_pct)) && nextdivergent < divergent && _switch == -1 && s.period.stoch_K > s.options.stoch_k_sell) { s.signal = 'sell' } else if (s.period.close < (LowerBand / 100) * (100 + s.options.bollinger_lower_bound_pct) && nextdivergent >= divergent && _switch == 1 && s.period.stoch_K < s.options.stoch_k_buy) { s.signal = 'buy' } } cb() }).catch(function(){ cb()}) }).catch(function(){ cb()}) }, onReport: function (s) { var cols = [] if (s.period.report) { let upperBound = s.period.report.UpperBand let lowerBound = s.period.report.LowerBand var color = 'grey' if (s.period.close > (upperBound / 100) * ( 100 + s.options.bollinger_upper_bound_pct)) { color = 'green' } if (s.period.close < (lowerBound / 100) * ( 100 - s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.stoch_D).format('0.0000').substring(0,7), ' ').cyan) cols.push(z(8, n(s.period.stoch_K).format('0.0000').substring(0,7), ' ').cyan) cols.push(z(5, n(s.period.divergent).format('0').substring(0,7), ' ').cyan) cols.push(z(2, n(s.period._switch).format('0').substring(0,2), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.ListOption(['1m', '2m', '3m', '4m', '5m', '10m','15m']),//, '10m','15m','30m','45m','60m' min_periods: Phenotypes.Range(52, 150), markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), markup_sell_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0, 0.1), profit_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), // -- strategy rsi_periods: Phenotypes.Range(10, 30), stoch_periods: Phenotypes.Range(5, 30), stoch_k: Phenotypes.Range(1, 10), stoch_d: Phenotypes.Range(1, 10), stoch_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), stoch_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), bollinger_size: Phenotypes.RangeFactor(10, 25, 1), bollinger_time: Phenotypes.RangeFactor(1, 3.0, 0.1), bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0), bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0) } } ================================================ FILE: extensions/strategies/trend_bollinger/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , bollinger = require('../../../lib/bollinger') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'trend_bollinger', description: 'Buy when (Signal ≤ Lower Bollinger Band && trend up) and sell when (Signal ≥ Upper Bollinger Band && trend down).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('bollinger_size', 'period size', Number, 20) this.option('bollinger_time', 'times of standard deviation between the upper band and the moving averages', Number, 2) this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 0) this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) }, calculate: function (s) { // calculate Bollinger Bands bollinger(s, 'bollinger', s.options.bollinger_size) }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.oversold_rsi === 'number') { if (s.oversold) { s.oversold = false s.trend = 'oversold' s.signal = 'buy' s.cancel_down = true return cb() } } if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { s.signal = null // hold let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { s.last_hit_bollinger = 'upper' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { s.last_hit_bollinger = 'lower' } else { if (s.last_hit_bollinger === 'upper' && s.period.close < s.last_hit_close) { s.trend = 'down' } else if (s.last_hit_bollinger === 'lower' && s.period.close > s.last_hit_close) { s.trend = 'up' } s.last_hit_bollinger = 'middle' } s.last_hit_close = s.period.close if (s.trend === 'down') { s.signal = 'sell' s.trend = null } else if (s.trend === 'up') { s.signal = 'buy' s.trend = null } } } cb() }, onReport: function (s) { var cols = [] if (s.period.bollinger) { if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { let upperBound = s.period.bollinger.upperBound let lowerBound = s.period.bollinger.lowerBound var color = 'grey' if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { color = 'green' } else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { color = 'red' } cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) } } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy bollinger_size: Phenotypes.Range(1, 40), bollinger_time: Phenotypes.RangeFloat(1,6), bollinger_upper_bound_pct: Phenotypes.RangeFloat(-1, 30), bollinger_lower_bound_pct: Phenotypes.RangeFloat(-1, 30) } } ================================================ FILE: extensions/strategies/trend_ema/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , ema = require('../../../lib/ema') , rsi = require('../../../lib/rsi') , stddev = require('../../../lib/stddev') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'trend_ema', description: 'Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '2m') this.option('period_length', 'period length, same as --period', String, '2m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('trend_ema', 'number of periods for trend EMA', Number, 26) this.option('neutral_rate', 'avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter)', Number, 'auto') this.option('oversold_rsi_periods', 'number of periods for oversold RSI', Number, 14) this.option('oversold_rsi', 'buy when RSI reaches this value', Number, 10) }, calculate: function(s) { ema(s, 'trend_ema', s.options.trend_ema) if (s.options.oversold_rsi) { // sync RSI display with oversold RSI periods s.options.rsi_periods = s.options.oversold_rsi_periods rsi(s, 'oversold_rsi', s.options.oversold_rsi_periods) if (!s.in_preroll && s.period.oversold_rsi <= s.options.oversold_rsi && !s.oversold && !s.cancel_down) { s.oversold = true if (s.options.mode !== 'sim' || s.options.verbose) console.log(('\noversold at ' + s.period.oversold_rsi + ' RSI, preparing to buy\n').cyan) } } if (s.period.trend_ema && s.lookback[0] && s.lookback[0].trend_ema) { s.period.trend_ema_rate = (s.period.trend_ema - s.lookback[0].trend_ema) / s.lookback[0].trend_ema * 100 } if (s.options.neutral_rate === 'auto') { stddev(s, 'trend_ema_stddev', Math.floor(s.options.trend_ema / 2), 'trend_ema_rate') } else { s.period.trend_ema_stddev = s.options.neutral_rate } }, onPeriod: function (s, cb) { if (!s.in_preroll && typeof s.period.oversold_rsi === 'number') { if (s.oversold) { s.oversold = false s.trend = 'oversold' s.signal = 'buy' s.cancel_down = true return cb() } } if (typeof s.period.trend_ema_stddev === 'number') { if (s.period.trend_ema_rate > s.period.trend_ema_stddev) { if (s.trend !== 'up') { s.acted_on_trend = false } s.trend = 'up' s.signal = !s.acted_on_trend ? 'buy' : null s.cancel_down = false } else if (!s.cancel_down && s.period.trend_ema_rate < (s.period.trend_ema_stddev * -1)) { if (s.trend !== 'down') { s.acted_on_trend = false } s.trend = 'down' s.signal = !s.acted_on_trend ? 'sell' : null } } cb() }, onReport: function(s) { var cols = [] if (typeof s.period.trend_ema_stddev === 'number') { var color = 'grey' if (s.period.trend_ema_rate > s.period.trend_ema_stddev) { color = 'green' } else if (s.period.trend_ema_rate < s.period.trend_ema_stddev * -1) { color = 'red' } cols.push(z(8, n(s.period.trend_ema_rate).format('0.0000'), ' ')[color]) if (s.period.trend_ema_stddev) { cols.push(z(8, n(s.period.trend_ema_stddev).format('0.0000'), ' ').grey) } } else { if (s.period.trend_ema_stddev) { cols.push(' ') } else { cols.push(' ') } } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 100), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy trend_ema: Phenotypes.Range(1, 40), oversold_rsi_periods: Phenotypes.Range(5, 50), oversold_rsi: Phenotypes.Range(20, 100) }, } ================================================ FILE: extensions/strategies/trendline/README.md ================================================ ## Reading the console output ![console](Capture.PNG) From left to right ( for trendline not pictured above, which is neural ): - Timestamp in local time (grey, blue when showing "live" stats) - Asset price in currency (yellow) - Percent change of price since last period (red/green) - Volume in asset since last period (grey) - [RSI](http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi) ANSI graph (red/green) - strategy inormation, in order: ``` - col1: trendline 10000/1000 trades - col2: trendline 1000/100 trades - col3:stdev of 10000 trades - col4: stdev of 1000 trades - col5: 10000trades mean - col6: 1000 trades mean - col7: the mean of the 10000 & 1000 trades and stdev calculated into 100* the stdev percentage of the mean of the long and short trades (in short the active-markup based on a multiplier to create a percentage of standard deviation.) - If the four cols on the right are green, that means its a currently increasing trend) when both on the left are green both trends are increasing) ``` - Current signal or action, including `buy`, `sell`, `buying`, `selling`, `bought`, `sold` and `last_trade_worth` (percent change in the trend direction since last buy/sell) - Account balance (asset) - Account balance (currency) - Profit or loss percent (can be reset with `--reset_profit`) - Gain or loss vs. buy/hold strategy ================================================ FILE: extensions/strategies/trendline/strategy.js ================================================ let math = require('mathjs') , trend = require('trend') , z = require('zero-fill') , n = require('numbro') , stats = require('stats-lite') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') var oldgrowth = 1 module.exports = { name: 'trendline', description: 'Calculate a trendline and trade when trend is positive vs negative.', getOptions: function () { this.option('period', 'period length', String, '30s') this.option('period_length', 'period length', String, '30s') this.option('lastpoints', 'Number of trades for short trend average', Number, 100) this.option('avgpoints', 'Number of trades for long trend average', Number, 1000) this.option('lastpoints2', 'Number of trades for short trend average', Number, 10) this.option('avgpoints2', 'Number of trades for long trend average', Number, 100) this.option('min_periods', 'Basically avgpoints + a BUNCH of more preroll periods for anything less than 5s period', Number, 15000) this.option('markup_sell_pct', 'test', Number, 0) this.option('markdown_buy_pct', 'test', Number, 0) }, calculate: function () { }, onPeriod: function (s, cb) { ema(s, 'trendline', s.options.trendline) var tl1 = [] var tls = [] var tll = [] if (s.lookback[s.options.avgpoints + 2000]) { for (let i = 0; i < s.options.avgpoints + 1000; i++) { tl1.push(s.lookback[i].close) } for (let i = 0; i < s.options.lastpoints; i++) { tls.push(s.lookback[i].close) } for (let i = 0; i < s.options.avgpoints; i++) { tll.push(s.lookback[i].close) } var chart = tl1 var growth = trend(chart, { lastPoints: s.options.lastpoints, avgPoints: s.options.avgpoints, avgMinimum: 0, reversed: true }) var growth2 = trend(chart, { lastPoints: s.options.lastpoints2, avgPoints: s.options.avgpoints2, avgMinimum: 0, reversed: true }) s.stats = growth s.growth = growth > 1 s.stats2 = growth2 s.growth2 = growth2 > 1 s.stdevs = stats.stdev(tls) s.stdevl = stats.stdev(tll) s.means = math.mean(tls) s.meanl = math.mean(tll) s.pcts = s.stdevs / s.means s.pctl = s.stdevl / s.meanl s.options.markup_sell_pct = math.mean(s.pcts, s.pctl) * 100 s.options.markdown_buy_pct = math.mean(s.pcts, s.pctl) * 100 s.accel = growth > oldgrowth oldgrowth = growth } if ( s.growth === true && s.growth2 === true ) { s.signal = 'buy' } else if ( s.growth === false | s.growth2 === false | s.accel === false ) { //s.signal = 'sell' } cb() }, onReport: function (s) { var cols = [] cols.push(' ') cols.push(z(8, n(s.stats).format('0.00000000'), ' ')[s.growth === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.stats2).format('0.00000000'), ' ')[s.growth2 === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.stdevs).format('0.00000000'), ' ')[s.accel === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.stdevl).format('0.00000000'), ' ')[s.accel === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.means).format('0.00000000'), ' ')[s.accel === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.meanl).format('0.00000000'), ' ')[s.accel === true ? 'green' : 'red']) cols.push(' ') cols.push(z(8, n(s.options.markup_sell_pct).format('0.00000000'), ' ')[s.accel === true ? 'green' : 'red']) return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 400, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy lastpoints: Phenotypes.Range(20, 500), avgpoints: Phenotypes.Range(300, 3000), lastpoints2: Phenotypes.Range(5, 300), avgpoints2: Phenotypes.Range(50, 1000), } } ================================================ FILE: extensions/strategies/trust_distrust/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'trust_distrust', description: 'Sell when price higher than $sell_min% and highest point - $sell_threshold% is reached. Buy when lowest price point + $buy_threshold% reached.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') this.option('min_periods', 'min. number of history periods', Number, 52) this.option('sell_threshold', 'sell when the top drops at least below this percentage', Number, 2) this.option('sell_threshold_max', 'sell when the top drops lower than this max, regardless of sell_min (panic sell, 0 to disable)', Number, 0) this.option('sell_min', 'do not act on anything unless the price is this percentage above the original price', Number, 1) this.option('buy_threshold', 'buy when the bottom increased at least above this percentage', Number, 2) this.option('buy_threshold_max', 'wait for multiple buy signals before buying (kill whipsaw, 0 to disable)', Number, 0) this.option('greed', 'sell if we reach this much profit (0 to be greedy and either win or lose)', Number, 0) }, calculate: function (s) { if (typeof s.trust_distrust_start_greed === 'undefined') { s.trust_distrust_start_greed = s.period.high } if (typeof s.trust_distrust_start === 'undefined') { s.trust_distrust_start = s.period.high } if (typeof s.trust_distrust_highest === 'undefined') { s.trust_distrust_highest = s.period.high } if (typeof s.trust_distrust_lowest === 'undefined') { s.trust_distrust_lowest = s.period.high } if (typeof s.trust_distrust_last_action === 'undefined') { s.trust_distrust_last_action = null } if (typeof s.trust_distrust_buy_threshold_max === 'undefined') { s.trust_distrust_buy_threshold_max = 0 } // when our current price is higher than what we recorded, overwrite if (s.period.high > s.trust_distrust_highest) { s.trust_distrust_highest = s.period.high } // when our current price is lower than what we recorded, overwrite if (s.trust_distrust_lowest > s.period.high) { s.trust_distrust_lowest = s.period.high } }, onPeriod: function (s, cb) { if (s.greedy) { s.signal = s.trust_distrust_last_action return cb() } // sell logic if (s.trust_distrust_last_action !== 'sell') { if ( s.period.high > (s.trust_distrust_start + (s.trust_distrust_start / 100 * s.options.sell_min))) { // we are above minimum we want to sell for, or going so low we should "panic sell" if (s.period.high < (s.trust_distrust_highest - (s.trust_distrust_highest / 100 * s.options.sell_threshold))) { // we lost sell_threshold from highest point s.signal = 'sell' s.trust_distrust_last_action = 'sell' s.trust_distrust_start = s.period.high s.trust_distrust_highest = s.period.high s.trust_distrust_lowest = s.period.high return cb() } } if (s.options.sell_threshold_max > 0 && s.period.high < (s.trust_distrust_highest - (s.trust_distrust_highest / 100 * s.options.sell_threshold_max))) { // we panic sell s.signal = 'sell' s.trust_distrust_last_action = 'sell' s.trust_distrust_start = s.period.high s.trust_distrust_highest = s.period.high s.trust_distrust_lowest = s.period.high return cb() } } if (s.options.greed > 0 && s.period.high > (s.trust_distrust_start_greed + (s.trust_distrust_start_greed / 100 * s.options.greed))) { // we are not greedy, sell if this profit is reached s.signal = 'sell' s.trust_distrust_last_action = 'sell' s.trust_distrust_start = s.period.high s.trust_distrust_highest = s.period.high s.trust_distrust_lowest = s.period.high s.greedy = true return cb() } // buy logic if (s.trust_distrust_last_action !== 'buy') { if(s.period.high < s.trust_distrust_start && s.period.high > (s.trust_distrust_lowest + (s.trust_distrust_lowest / 100 * s.options.buy_threshold))) { // we grew above buy threshold from lowest point if (s.options.buy_threshold_max > 0 && s.trust_distrust_buy_threshold_max < s.options.buy_threshold_max) { s.trust_distrust_buy_threshold_max++ return cb() } s.trust_distrust_buy_threshold_max = 0 s.signal = 'buy' s.trust_distrust_last_action = 'buy' s.trust_distrust_start = s.period.high s.trust_distrust_highest = s.period.high s.trust_distrust_lowest = s.period.high return cb() } } // repeat last signal if (s.signal === null) { s.signal = s.trust_distrust_last_action } return cb() }, onReport: function (s) { var cols = [] var color = 'grey' if (s.period.high > s.trust_distrust_start) { color = 'green' } else if (s.period.high < s.trust_distrust_lowest) { color = 'red' } cols.push(z(8, n(s.period.high).format('0.0000'), ' ')[color]) cols.push(z(8, n(s.trust_distrust_start).format('0.0000'), ' ').grey) return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 100), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy sell_threshold: Phenotypes.Range(1, 100), sell_threshold_max: Phenotypes.Range0(1, 100), sell_min: Phenotypes.Range(1, 100), buy_threshold: Phenotypes.Range(1, 100), buy_threshold_max: Phenotypes.Range0(1, 100), greed: Phenotypes.Range(1, 100) } } ================================================ FILE: extensions/strategies/vpt/strategy.js ================================================ module.exports = { name: 'vpt', description: 'Vpt - Volume Price Trend Indicator.', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '30m') this.option('period_length', 'period length, same as --period', String, '30m') this.option('min_periods', 'min. number of history periods', Number, 50) }, // called first, but without lookback, working on s.period calculate: function(s) { if(s.lookback && s.lookback[0] && s.lookback[0].vpt){ //s.period.vpt = s.lookback[0].volume + s.period.volume * ((s.period.close - s.lookback[0].close)/s.lookback[0].close) s.period.vpt = s.lookback[0].vpt + s.period.volume * ((s.period.close - s.lookback[0].close)/s.lookback[0].close) } else if(s.lookback && s.lookback[0]){ s.period.vpt = s.period.volume + s.period.volume * ((s.period.close - s.lookback[0].close)/s.lookback[0].close) } }, onPeriod: function (s, cb) { if(s.lookback.length >= 1) { if(s.period.vpt > s.lookback[0].vpt) s.trend = "up" else s.trend = "down" // if(s.trend == 'up') // s.signal = 'buy' // else // s.signal = 'sell' } cb() }, onReport: function(s) { var cols = [] if(s) { return cols } else { return cols } } } ================================================ FILE: extensions/strategies/wavetrend/strategy.js ================================================ var z = require('zero-fill') , n = require('numbro') , wto = require('../../../lib/wto') , ema = require('../../../lib/ema') , Phenotypes = require('../../../lib/phenotype') module.exports = { name: 'wavetrend', description: 'Buy when (Signal < Oversold) and sell when (Signal > Overbought).', getOptions: function () { this.option('period', 'period length, same as --period_length', String, '1h') this.option('period_length', 'period length, same as --period', String, '1h') this.option('min_periods', 'min. number of history periods', Number, 21) this.option('wavetrend_channel_length', 'wavetrend channel length', Number, 10) this.option('wavetrend_average_length', 'wavetrend average length', Number, 21) this.option('wavetrend_overbought_1', 'wavetrend overbought limit 1', Number, 60) this.option('wavetrend_overbought_2', 'wavetrend overbought limit 2', Number, 53) this.option('wavetrend_oversold_1', 'wavetrend oversold limit 1', Number, -60) this.option('wavetrend_oversold_2', 'wavetrend oversold limit 2', Number, -53) this.option('wavetrend_trends', 'act on trends instead of limits', Boolean, false) }, calculate: function (s) { // calculate Wavetrend and EMA wto(s, 'wto', s.options.wavetrend_channel_length) ema(s, 'ema', s.options.wavetrend_channel_length) }, onPeriod: function (s, cb) { if (s.period.wto) { s.signal = null // hold let prev_wto = s.lookback[0].wto let wto = s.period.wto let prev_hcl3 = s.lookback[0].hcl3 let hcl3 = s.period.hcl3 let prev_ema = s.lookback[0].ema let ema = s.period.ema if (!s.sell_signal_close) s.sell_signal_close = 0 if (!s.buy_signal_close) s.buy_signal_close = 0 if (!s.sell_pct_orig) s.sell_pct_orig = s.sell_pct if (!s.buy_pct_orig) s.buy_pct_orig = s.sell_pct s.options.wavetrend_trends = (s.options.wavetrend_trends === 'true' || s.options.wavetrend_trends === true) if (s.options.wavetrend_trends === true) { if (wto > prev_wto) { if (s.trend === 'down' && s.buy_signal_close < s.period.close) { //console.log('\n') //console.log(s.period.hcl3, s.period.wto, s.lookback[0].wto, s.buy_signal_close) //console.log('trend reversal, we should sell') s.signal = 'sell' s.sell_signal_close = s.period.close } s.trend = 'up' } if (wto < prev_wto) { if (s.trend === 'up' && s.sell_signal_close > s.period.close) { //console.log('\n') //console.log(s.period.hcl3, s.period.wto, s.lookback[0].wto, s.sell_signal_close) //console.log('trend reversal, we should buy') s.signal = 'buy' s.buy_signal_close = s.period.close } s.trend = 'down' } } if (s.options.wavetrend_trends === false) { if ((wto < s.options.wavetrend_overbought_2) && (prev_wto < s.options.wavetrend_overbought_2)) { s.sell_pct = 99 //console.log('\n') //console.log(prev_wto, wto, prev_hcl3, hcl3, prev_ema, ema) //console.log('trend reversal, we should sell') if (prev_wto > wto && prev_hcl3 > hcl3 && prev_ema > ema) { if (s.trend === 'down' && s.buy_signal_close < s.period.close) { s.signal = 'sell' s.sell_signal_close = s.period.close } s.trend = 'up' } } else if ((wto > s.options.wavetrend_oversold_2) && (prev_wto > s.options.wavetrend_oversold_2)) { s.buy_pct = 99 //console.log('\n') //console.log(prev_wto, wto, prev_hcl3, hcl3, prev_ema, ema) //console.log('trend reversal, we should buy') if (prev_wto < wto && prev_hcl3 < hcl3 && prev_ema < ema) { if (s.trend === 'up' && s.sell_signal_close > s.period.close) { s.signal = 'buy' s.buy_signal_close = s.period.close } s.trend = 'down' } } else if ((wto < s.options.wavetrend_overbought_1) && (prev_wto < s.options.wavetrend_overbought_1)) { s.sell_pct = 5 //console.log('\n') //console.log(prev_wto, wto, prev_hcl3, hcl3, prev_ema, ema) //console.log('trend reversal, we should sell') if (prev_wto > wto && prev_hcl3 > hcl3 && prev_ema > ema) { if (s.trend === 'down' && s.buy_signal_close < s.period.close) { s.signal = 'sell' s.sell_signal_close = s.period.close } s.trend = 'up' } } else if ((wto > s.options.wavetrend_oversold_1) && (prev_wto > s.options.wavetrend_oversold_1)) { s.buy_pct = 5 //console.log('\n') //console.log(prev_wto, wto, prev_hcl3, hcl3, prev_ema, ema) //console.log('trend reversal, we should buy') if (prev_wto < wto && prev_hcl3 < hcl3 && prev_ema < ema) { if (s.trend === 'up' && s.sell_signal_close > s.period.close) { s.signal = 'buy' s.buy_signal_close = s.period.close } s.trend = 'down' } } else { s.sell_pct = 1 s.buy_pct = 1 if (wto > prev_wto) { if (s.trend === 'down' && s.buy_signal_close < s.period.close) { //console.log('\n') //console.log(s.period.hcl3, s.period.wto, s.lookback[0].wto, s.buy_signal_close) //console.log('trend reversal, we should sell') s.signal = 'sell' s.sell_signal_close = s.period.close } s.trend = 'up' } if (wto < prev_wto) { if (s.trend === 'up' && s.sell_signal_close > s.period.close) { //console.log('\n') //console.log(s.period.hcl3, s.period.wto, s.lookback[0].wto, s.sell_signal_close) //console.log('trend reversal, we should buy') s.signal = 'buy' s.buy_signal_close = s.period.close } s.trend = 'down' } } } } cb() }, onReport: function (s) { var cols = [] if (s.period.wto) { var color = 'grey' if (s.period.hcl3 > s.lookback[0].hcl3) { color = 'green' } else if (s.period.hcl3 < s.lookback[0].hcl3) { color = 'red' } cols.push(z(8, n(s.period.hcl3).format('+00.0000'), ' ')[color]) cols.push(z(8, n(s.period.wto).format('00'), ' ').cyan) cols.push(z(8, n(s.lookback[0].wto).format('00'), ' ').cyan) } else { cols.push(' ') } return cols }, phenotypes: { // -- common period_length: Phenotypes.RangePeriod(1, 120, 'm'), min_periods: Phenotypes.Range(1, 200), markdown_buy_pct: Phenotypes.RangeFloat(-1, 5), markup_sell_pct: Phenotypes.RangeFloat(-1, 5), order_type: Phenotypes.ListOption(['maker', 'taker']), sell_stop_pct: Phenotypes.Range0(1, 50), buy_stop_pct: Phenotypes.Range0(1, 50), profit_stop_enable_pct: Phenotypes.Range0(1, 20), profit_stop_pct: Phenotypes.Range(1,20), // -- strategy wavetrend_channel_length: Phenotypes.Range(1,20), wavetrend_average_length: Phenotypes.Range(1,42), wavetrend_overbought_1: Phenotypes.Range(1, 100), wavetrend_overbought_2: Phenotypes.Range(1,100), wavetrend_oversold_1: Phenotypes.Range(-100,0), wavetrend_oversold_2: Phenotypes.Range(-100,0), wavetrend_trends: Phenotypes.ListOption([true, false]) } } ================================================ FILE: lib/_data-structures/Queue.js ================================================ //module.exports = (function container (get, set, clear) { module.exports = //code.stephenmorley.org /*return*/ function Queue(){var a=[],b=0;this.getLength=function(){return a.length-b};this.isEmpty=function(){return 0==a.length};this.enqueue=function(b){a.push(b)};this.dequeue=function(){if(0!=a.length){var c=a[b];2*++b>=a.length&&(a=a.slice(b),b=0);return c}};this.peek=function(){return 0 s.lookback[0].low-s.period.low ? Math.max(s.period.high-s.lookback[0].high, 0): 0 let DirectionalMovementMinus = s.lookback[0].low-s.period.low > s.period.high-s.lookback[0].high ? Math.max(s.lookback[0].low-s.period.low, 0): 0 s.period['SmoothedTrueRange'] = (s.lookback[0]['SmoothedTrueRange'] == undefined) ? TrueRange : s.lookback[0]['SmoothedTrueRange'] - s.lookback[0]['SmoothedTrueRange']/length + TrueRange s.period['SmoothedDirectionalMovementPlus'] = (s.lookback[0]['SmoothedDirectionalMovementPlus'] == undefined) ? DirectionalMovementPlus : s.lookback[0]['SmoothedDirectionalMovementPlus'] - s.lookback[0]['SmoothedDirectionalMovementPlus']/length + DirectionalMovementPlus s.period['SmoothedDirectionalMovementMinus'] = (s.lookback[0]['SmoothedDirectionalMovementMinus'] == undefined) ? DirectionalMovementMinus : s.lookback[0]['SmoothedDirectionalMovementMinus'] - s.lookback[0]['SmoothedDirectionalMovementMinus']/length + DirectionalMovementMinus s.period['DIPlus'] = s.period['SmoothedDirectionalMovementPlus'] / s.period['SmoothedTrueRange'] * 100 s.period['DIMinus'] = s.period['SmoothedDirectionalMovementMinus'] / s.period['SmoothedTrueRange'] * 100 } if (s.lookback.length > length) { let ADX = s.lookback .slice(0, length) .reduce((sum, cur) => { let DX = Math.abs(cur['DIPlus']-cur['DIMinus']) / (cur['DIPlus']+cur['DIMinus'])*100 return sum + DX }, 0) s.period[key] = ADX / length } } ================================================ FILE: lib/backtester.js ================================================ let _ = require('lodash') , moment = require('moment') , argv = require('yargs').argv , tb = require('timebucket') , readline = require('readline') , z = require('zero-fill') , n = require('numbro') , shell = require('shelljs') , StripAnsi = require('strip-ansi') , path = require('path') , fs = require('fs') , roundp = require('round-precision') , Phenotypes = require('./phenotype') const spawn = require('child_process').spawn let simArgs, simTotalCount, parallelLimit, writeFile let processOutput = function (output, taskStrategyName, pheno) { let selector = pheno.selector || pheno.exchangeMarketPair let tFileName = path.resolve(__dirname, '..', 'simulations', 'sim_' + taskStrategyName.replace('_', '') + '_' + selector.toLowerCase().replace('_', '') + '_' + pheno.backtester_generation + '.json') let simulationResults let outputArray let params let assetPriceLastBuy let lastAssestValue let assetCapital let profit let startCapital let endBalance let buyHold let vsBuyHold //let wlMatch //let errMatch let wins let losses let errorRate let days let start let end // This can retrieve the results from 2 different places. It defaults to reading it from the json file // but if no file is found it will fall back to the older metheod of scraping the output of the sim process // stdio scraping to be removed after full verification of functionality. // todo: see above comment if (fs.existsSync(tFileName)) { let jsonBuffer jsonBuffer = fs.readFileSync(tFileName, { encoding: 'utf8' }) simulationResults = JSON.parse(jsonBuffer) fs.unlinkSync(tFileName) } // If somehow the sim file failed to write, this will most often recover it by parsing the last output if (typeof (simulationResults) !== 'object') { // Find everything between the first { and last } outputArray = output.split('{') outputArray.shift() output = outputArray.join('{') outputArray = output.split('}') outputArray.pop() output = outputArray.join('}') simulationResults = JSON.parse(`{${output}}`) } if (typeof (simulationResults) === 'object' && typeof simulationResults.simresults !== typeof undefined) { params = simulationResults endBalance = simulationResults.simresults.currency assetPriceLastBuy = simulationResults.simresults.last_buy_price lastAssestValue = simulationResults.simresults.last_assest_value assetCapital = simulationResults.simresults.asset_capital startCapital = simulationResults.simresults.start_capital profit = simulationResults.simresults.profit buyHold = simulationResults.simresults.buy_hold vsBuyHold = simulationResults.simresults.vs_buy_hold //wlMatch = (simulationResults.simresults.total_sells - simulationResults.simresults.total_losses) +'/'+ simulationResults.simresults.total_losses wins = simulationResults.simresults.total_sells - simulationResults.simresults.total_losses losses = simulationResults.simresults.total_losses errorRate = simulationResults.simresults.total_losses / simulationResults.simresults.total_sells days = parseInt(simulationResults.days) start = parseInt(simulationResults.start) end = parseInt(simulationResults.end || null) } else { console.log(`Couldn't find simulationResults for ${pheno.backtester_generation}`) console.log(pheno.command.commandString) // this should return a general bad result but not throw an error // our job here is to use the result. not diagnose an error at this point so a failing sim should just be ignored. // idea here is to make the fitness of this calculation as bad as possible so darwin won't use the combonation of parameters again. // todo: make the result its own object, and in this function just set the values don't define the result here. return { params: 'module.exports = {}', endBalance: 0, buyHold: 0, vsBuyHold: 0, lastAssestValue: 0, assetPriceLastBuy:0, wins: 0, losses: -1, errorRate: 100, days: 0, period_length: 0, min_periods: 0, markdown_buy_pct: 0, markup_sell_pct: 0, order_type: 'maker', wlRatio: 'Infinity', roi: -1000, selector: selector, strategy: taskStrategyName, frequency: 0, assetCapital:0, startCapital:0, profit:0 } } if (typeof params === 'undefined') { console.log('busted params') console.log(`output: ${JSON.stringify(output)}`) console.log(`simulationResults: ${JSON.stringify(simulationResults)}`) } let roi if (params.currency_capital == 0.0) { roi = roundp(endBalance, 3) } else { roi = roundp(((endBalance - params.currency_capital) / params.currency_capital) * 100, 3) } //todo: figure out what this is trying to do. let r = params delete r.asset_capital delete r.buy_pct delete r.currency_capital delete r.days delete r.mode delete r.order_adjust_time delete r.population delete r.population_data delete r.sell_pct delete r.start delete r.end delete r.stats delete r.use_strategies delete r.verbose delete r.simresults delete r.silent delete r.generateLaunch delete r.ignoreLaunchFitness delete r.maxCores delete r.minTrades delete r.noStatSave delete r.filename //delete r.fitnessCalcType r.selector = r.selector.normalized if (start) { r.start = moment(start).format('YYYYMMDDHHmm') } if (end) { r.end = moment(end).format('YYYYMMDDHHmm') } if (!start && !end && params.days) { r.days = params.days } if (!days) { days = parseInt(argv.days, 10) } if (!days || days < 1) days = 1 let results = { params: 'module.exports = ' + JSON.stringify(r), assetPriceLastBuy: assetPriceLastBuy, lastAssestValue: lastAssestValue, profit: profit, assetCapital: assetCapital, startCapital: startCapital, endBalance: parseFloat(endBalance), buyHold: parseFloat(buyHold), vsBuyHold: parseFloat(vsBuyHold) || vsBuyHold, wins: wins, losses: losses, errorRate: parseFloat(errorRate), days: days, period_length: params.period_length, min_periods: params.min_periods, markdown_buy_pct: params.markdown_buy_pct, markup_sell_pct: params.markup_sell_pct, order_type: params.order_type, wlRatio: losses > 0 ? roundp(wins / losses, 3) : 'Infinity', roi: roi, selector: params.selector, strategy: params.strategy, frequency: roundp((wins + losses) / days, 3) } return results } let runUpdate = function (days, selector) { let zenbot_cmd = process.platform === 'win32' ? 'zenbot.bat' : './zenbot.sh' let command = `${zenbot_cmd} backfill --days=${days} ${selector}` console.log('Backfilling (might take some time) ...') console.log(command) shell.exec(command, { silent: true, async: false }) } let ensureDirectoryExistence = function (filePath) { var dirname = path.dirname(filePath) if (fs.existsSync(dirname)) { return true } ensureDirectoryExistence(dirname) fs.mkdirSync(dirname) } let monitor = { periodDurations: [], phenotypes: [], distanceOfTimeInWords: (timeA, timeB) => { var hourDiff = timeA.diff(timeB, 'hours') let minDiff = 0 if (hourDiff == 0) { minDiff = timeA.diff(timeB, 'minutes') var secDiff = timeA.clone().subtract(minDiff, 'minutes').diff(timeB, 'seconds') return `${minDiff}m ${secDiff}s` } else { minDiff = timeA.clone().subtract(hourDiff, 'hours').diff(timeB, 'minutes') return `${hourDiff}h ${minDiff}m` } }, actualRange: function (so) { // Adapted from sim.js logic to similarly figure out how much time is being processed if (so.start) { so.start = moment(so.start, 'YYYYMMDDHHmm') if (so.days && !so.end) { so.end = so.start.clone().add(so.days, 'days') } } if (so.end) { so.end = moment(so.end, 'YYYYMMDDHHmm') if (so.days && !so.start) { so.start = so.end.clone().subtract(so.days, 'days') } } if (!so.start && so.days) { so.start = moment().subtract(so.days, 'days') } if (so.days && !so.end) { so.end = so.start.clone().add(so.days, 'days') } if (so.start && so.end) { var actualStart = moment(tb(so.start.valueOf()).resize(so.period_length).subtract(so.min_periods + 2).toMilliseconds()) return { start: actualStart, end: so.end } } return { start: so.start, end: so.end } }, reportStatus: function () { var genCompleted = 0 // var genTotal = 0 var simsDone = 0 var simsActive = 0 var simsErrored = 0 var simsAll = simTotalCount var simsRemaining = simsAll // var self = this // console.log(`simsAll: ${simsAll}, this.phenotypes: ${this.phenotypes.length}`); readline.clearLine(process.stdout) readline.cursorTo(process.stdout, 0) var inProgress = [] var inProgressStr = [] var slowestP = null var slowestEta = null var bestP = null var bestBalance = null this.phenotypes.forEach(function (p) { if ('sim' in p) { if (Object.keys(p.sim).length === 0) { simsActive++ inProgress.push(p) } else { simsDone++ if (!p.command || !p.command.result) simsErrored++ if (p.command) { let balance = p.command.result.endBalance if (bestP == null || bestBalance < balance) { bestP = p bestBalance = balance } else if (bestP && bestBalance == balance && bestP.command.iteration > p.command.iteration) { // Always pick the earliest one so it doesn't look like the number is jumping all over the place bestP = p bestBalance = balance } } } simsRemaining-- } }) var homeStretchMode = simsActive < (parallelLimit - 1) && simsRemaining == 0 inProgress.forEach(function (p) { var c = p.command var currentTime if (c.currentTimeString) currentTime = moment(c.currentTimeString, 'YYYY-MM-DD HH:mm:ss') if (currentTime && currentTime.isBefore(c.queryStart)) c.queryStart = currentTime // console.log(`${c.iteration} currentTime: ${currentTime}, queryStart: ${c.queryStart}, queryEnd: ${c.queryEnd}, current: ${c.currentTimeString}`); // var timeSoFar = moment().diff(c.startTime); // console.log(`remaining: ${time} - ${timeSoFar} = ${time - timeSoFar}`); // timeLeft += time - timeSoFar; if (currentTime && c.queryStart && c.queryEnd) { var totalTime = c.queryEnd.diff(c.queryStart) // 2018-01-25 06:18:00 var progress = currentTime.diff(c.queryStart) // console.log(`totalTime: ${totalTime} vs progress: ${progress}`); var percentage = Math.min(progress / totalTime, 1) genCompleted += percentage var now = moment() var timeElapsed = now.diff(c.startTime) // console.log(`startTime: ${c.startTime}, timeElapsed: ${timeElapsed}, adding: ${timeElapsed / percentage}ms`); var eta = c.startTime.clone().add(timeElapsed / percentage, 'milliseconds') if (slowestP == null || slowestEta.isBefore(eta)) { slowestP = p slowestEta = eta } if (homeStretchMode) inProgressStr.push(`${(c.iteration + ':').gray} ${(percentage * 100).toFixed(1)}% ETA: ${monitor.distanceOfTimeInWords(eta, now)}`) else inProgressStr.push(`${(c.iteration + ':').gray} ${(percentage * 100).toFixed(1)}%`) } }) // timeLeft /= simsActive; // how many run at one time if (inProgressStr.length > 0) { // process.stdout.write("\u001b[1000D") // Move left process.stdout.write('\u001b[1A') readline.clearLine(process.stdout) readline.cursorTo(process.stdout, 0) process.stdout.write(inProgressStr.join(', ')) process.stdout.write('\n') } var percentage = ((simsDone + genCompleted) / simsAll * 100).toFixed(1) // z(8, n(s.period.trend_ema_rate).format('0.0000'), ' ')[color] process.stdout.write(`Done: ${simsDone.toString().green}, Active: ${simsActive.toString().yellow}, Remaining: ${simsRemaining.toString().gray}, `) if (simsErrored > 0) process.stdout.write(`Errored: ${simsErrored.toString().red}, `) process.stdout.write(`Completion: ${z(5, (n(percentage).format('0.0') + '%'), ' ').green} `) let bestBColor = 'gray' if (bestP) { if (argv.currency_capital) { let cc = parseFloat(argv.currency_capital) if (cc < 0.1) bestBColor = 'green' else if (cc > bestBalance) bestBColor = 'red' else bestBColor = 'yellow' } } let bestBalanceString = z(5, n(bestBalance || 0).format('0.0000'), ' ')[bestBColor] process.stdout.write(`Best Balance(${(bestP ? bestP.command.iteration.toString() : '?')[bestBColor]}): ${bestBalanceString}`) if (inProgressStr.length > 0) { if (!homeStretchMode) process.stdout.write(`, Slowest(${slowestP.command.iteration.toString().yellow}) ETA: ${monitor.distanceOfTimeInWords(slowestEta, moment()).yellow}`) } }, reset: function () { this.phenotypes.length = 0 }, start: function () { process.stdout.write('\n\n') this.generationStarted = moment() this.reportInterval = setInterval(() => { this.reportStatus() }, 1000) }, stop: function (label) { this.generationEnded = moment() clearInterval(this.reportInterval) var timeStr = this.distanceOfTimeInWords(this.generationEnded, this.generationStarted) console.log(`\n\n${label} completed at ${this.generationEnded.format('YYYY-MM-DD HH:mm:ss')}, took ${timeStr}, results saved to:`) } } module.exports = { init: function (options) { simArgs = options.simArgs simTotalCount = options.simTotalCount parallelLimit = options.parallelLimit writeFile = options.writeFile }, deLint: function () { //Clean up any generation files left over in the simulation directory //they will be overwritten, but best not to confuse the issue. //if it fails. doesn't matter they will be overwritten anyways. not need to halt the system. try { let tDirName = path.resolve(__dirname, '..', 'simulations') let tFileName = 'sim_' let files = fs.readdirSync(tDirName) for (let i = 0; i < files.length; i++) { if (files[i].lastIndexOf(tFileName) == 0) { let filePath = path.resolve(__dirname, '..', 'simulations', files[i]) fs.unlinkSync(filePath) } } } catch (err) { console.log('error deleting lint from prior run') } }, writeFileAndFolder: function (filePath, data) { ensureDirectoryExistence(filePath) fs.writeFileSync(filePath, data) }, ensureBackfill: function () { let days = argv.days if (!days) { if (argv.start) { var start = moment(argv.start, 'YYYYMMDDHHmm') days = Math.max(1, moment().diff(start, 'days')) } else { var end = moment(argv.end, 'YYYYMMDDHHmm') days = moment().diff(end, 'days') + 1 } } runUpdate(days, argv.selector) }, buildCommand: function (taskStrategyName, phenotype, filename) { var cmdArgs = Object.assign({}, phenotype) cmdArgs.strategy = taskStrategyName Object.assign(cmdArgs, simArgs) var selector = cmdArgs.selector delete cmdArgs.selector delete cmdArgs.exchangeMarketPair delete cmdArgs.sim delete cmdArgs.command delete cmdArgs.help delete cmdArgs.version if (argv.include_html) cmdArgs.filename = filename if (argv.silent) cmdArgs.silent = true cmdArgs.backtester_generation = phenotype.backtester_generation let zenbot_cmd = process.platform === 'win32' ? 'zenbot.bat' : './zenbot.sh' let command = `${zenbot_cmd} sim ${selector}` for (const [key, value] of Object.entries(cmdArgs)) { if (_.isBoolean(value)) { command += ` --${value ? '' : 'no-'}${key}` } else { command += ` --${key}=${value}` } } var actualRange = monitor.actualRange({ start: cmdArgs.start, end: cmdArgs.end, days: cmdArgs.days, period_length: cmdArgs.period_length, min_periods: (cmdArgs.min_periods || 1) }) return { commandString: command, queryStart: actualRange.start, queryEnd: actualRange.end } }, runCommand: (taskStrategyName, phenotype, command, cb) => { // console.log(`[ ${command.iteration}/${populationSize * selectedStrategies.length} ] ${command.commandString}`) phenotype['sim'] = {} phenotype['command'] = command command.startTime = moment() var cmdArgs = command.commandString.split(' ') var cmdName = cmdArgs.shift() const proc = spawn(cmdName, cmdArgs) var endData = '' proc.on('exit', () => { let result = null let stdout = endData.toString() try { result = processOutput(stdout, taskStrategyName, phenotype) command.endTime = moment() command.result = result writeFile(command.iteration, JSON.stringify(command)) phenotype['sim'] = result result['fitness'] = Phenotypes.fitness(phenotype) monitor.reportStatus() } catch (err) { console.log(`Bad output detected on sim ${command.iteration} while running:`) console.log(command.commandString) console.log(err.toString()) console.log(stdout) console.log(err.stack) } cb(null, result) }) proc.stdout.on('data', (data) => { if (data.length > 500) { endData = data // console.log(`${command.iteration}: ${data}`) } else { var str = StripAnsi(data.toString()), lines = str.split(/(\r?\n)/g) for (var i = 0; i < lines.length; i++) { var line = lines[i] // console.log(`${command.iteration}: ${line}`) if (line.indexOf('-') == 4 && line.indexOf(':') == 13) { var timeStr = line.slice(0, 20) command.currentTimeString = timeStr // console.log(`${command.iteration}: ${command.currentTimeString}`) } } } }) }, startMonitor: () => monitor.start(), stopMonitor: (label) => monitor.stop(label), resetMonitor: () => monitor.reset(), reportStatus: () => monitor.reportStatus(), trackPhenotype: function (phenotype) { monitor.phenotypes.push(phenotype) } } ================================================ FILE: lib/bollinger.js ================================================ // Bollinger Bands var bollingerbands = require('bollinger-bands') module.exports = function bollinger (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length > length) { // skip calculation if result already presented as we use historical data only, // no need to recalculate for each individual trade if (key in s.period) return let data = [] for (var i=length-1; i>=0; i--) { data.push(s.lookback[i][source_key]) } const result = bollingerbands(data, length, s.options.bollinger_time) const upperBound = result.upper[result.upper.length-1] const lowerBound = result.lower[result.lower.length-1] const midBound = result.mid[result.mid.length-1] const simple_result = { upperBound : upperBound, midBound: midBound, lowerBound : lowerBound } s.period[key] = simple_result } } ================================================ FILE: lib/cci.js ================================================ module.exports = function cci (s, key, length, c) { s.period['TP'] = (s.period.high + s.period.low + s.period.close) / 3 if (s.lookback.length >= length - 1) { let period_list = s.lookback .slice(0, length - 1) period_list.unshift(s.period) let avg_TP = period_list .reduce((sum, tp) => { return sum + tp.TP }, 0) s.period['avg_TP'] = avg_TP / length let meanDev = period_list .reduce((sum, cur) => { cur = Math.abs(cur.TP - s.period.avg_TP) return sum + cur }, 0) meanDev = meanDev / length let CCI = (s.period.TP - s.period.avg_TP) / (c * meanDev) s.period[key] = CCI } } /* CCI = (Typical Price - 20-period SMA of TP) / (.015 x Mean Deviation) Typical Price (TP) = (High + Low + Close)/3 Constant = .015 There are four steps to calculating the Mean Deviation. First, subtract the most recent 20-period average of the typical price from each period's typical price. Second, take the absolute values of these numbers. Third, sum the absolute values. Fourth, divide by the total number of periods (20). */ ================================================ FILE: lib/cmf.js ================================================ // Chaikin Money Flow module.exports = function cmf (s, key, length) { if (s.lookback.length >= length) { let MFV = 0, SOV = 0 s.lookback.slice(0, length).forEach(function(cur) { MFV += cur.volume * ((cur.close - cur.low) - (cur.high - cur.close)) / (cur.high - cur.low) SOV += cur.volume }) s.period[key] = MFV / SOV } } ================================================ FILE: lib/debug.js ================================================ const boot = require('../boot') const moment = require('moment') let debug = boot.debug module.exports = { flip: function() { module.exports.on = debug = !debug }, msg: function(str) { if (debug) { console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - ' + str) } }, on: debug } ================================================ FILE: lib/ema.js ================================================ module.exports = function ema (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length >= length) { var prev_ema = s.lookback[0][key] if (typeof prev_ema === 'undefined' || isNaN(prev_ema)) { var sum = 0 s.lookback.slice(0, length).forEach(function (period) { sum += period[source_key] }) prev_ema = sum / length } var multiplier = 2 / (length + 1) s.period[key] = (s.period[source_key] - prev_ema) * multiplier + prev_ema } } ================================================ FILE: lib/engine.js ================================================ let tb = require('timebucket') , moment = require('moment') , z = require('zero-fill') , n = require('numbro') // eslint-disable-next-line no-unused-vars , colors = require('colors') , abbreviate = require('number-abbreviate') , readline = require('readline') , path = require('path') , _ = require('lodash') , notify = require('./notify') , rsi = require('./rsi') , async = require('async') , lolex = require('lolex') , { formatAsset, formatPercent, formatCurrency } = require('./format') , debug = require('./debug') let clock let nice_errors = new RegExp(/(slippage protection|loss protection)/) module.exports = function (s, conf) { let eventBus = conf.eventBus eventBus.on('trade', queueTrade) eventBus.on('trades', onTrades) let so = s.options if(_.isUndefined(s.exchange)){ if (so.mode !== 'live') { s.exchange = require(path.resolve(__dirname, '../extensions/exchanges/sim/exchange'))(conf, s) } else { s.exchange = require(path.resolve(__dirname, `../extensions/exchanges/${so.selector.exchange_id}/exchange`))(conf) } } else if (so.mode === 'paper') { s.exchange = require(path.resolve(__dirname, '../extensions/exchanges/sim/exchange'))(conf, s) } if (!s.exchange) { console.error('cannot trade ' + so.selector.normalized + ': exchange not implemented') process.exit(1) } s.product_id = so.selector.product_id s.asset = so.selector.asset s.currency = so.selector.currency s.asset_capital = 0 if (typeof so.period_length == 'undefined') so.period_length = so.period else so.period = so.period_length let products = s.exchange.getProducts() products.forEach(function (product) { if (product.asset === s.asset && product.currency === s.currency) { s.product = product } }) if (!s.product) { console.error('error: could not find product "' + s.product_id + '"') process.exit(1) } if (s.exchange.dynamicFees) { s.exchange.setFees({asset: s.asset, currency: s.currency}) } if (so.mode === 'sim' || so.mode === 'paper') { s.balance = {asset: so.asset_capital, currency: so.currency_capital, deposit: 0} } else { s.balance = {asset: 0, currency: 0, deposit: 0} } function memDump () { if (!debug.on) return let s_copy = JSON.parse(JSON.stringify(s)) delete s_copy.options.mongo delete s_copy.lookback console.error(s_copy) } s.ctx = { option: function (name, desc, type, def) { if (typeof so[name] === 'undefined') { so[name] = def } } } let asset_col_width = 0 let deposit_col_width = 0 let currency_col_width = 0 s.lookback = [] s.day_count = 1 s.my_trades = [] s.my_prev_trades = [] s.vol_since_last_blink = 0 if (so.mode !== 'sim' && conf.output.api.on) { s.boot_time = (new Date).getTime() s.tz_offset = new Date().getTimezoneOffset() s.last_trade_id = 0 s.trades = [] } if (so.strategy) { s.strategy = require(path.resolve(__dirname, `../extensions/strategies/${so.strategy}/strategy`)) if (s.strategy.getOptions) { s.strategy.getOptions.call(s.ctx, s) } if (s.strategy.orderExecuted) { eventBus.on('orderExecuted', function(type) { s.strategy.orderExecuted(s, type, executeSignal) }) } } var notifier = notify(conf) function pushMessage(title, message) { if (so.mode === 'live' || so.mode === 'paper') { notifier.pushMessage(title, message) } } function onMessage(callback) { if (so.mode === 'live' || so.mode === 'paper') { notifier.onMessage(callback) } } function isFiat() { return !s.currency.match(/^BTC|ETH|XMR|USDT$/) } function initBuffer (trade) { let d = tb(trade.time).resize(so.period_length) let de = tb(trade.time).resize(so.period_length).add(1) s.period = { period_id: d.toString(), size: so.period_length, time: d.toMilliseconds(), open: trade.price, high: trade.price, low: trade.price, close: trade.price, volume: 0, close_time: de.toMilliseconds() - 1 } } function nextBuyForQuote(s, quote) { if (s.next_buy_price) return n(s.next_buy_price).format(s.product.increment, Math.floor) else return n(quote.bid).subtract(n(quote.bid).multiply(s.options.markdown_buy_pct / 100)).format(s.product.increment, Math.floor) } function nextSellForQuote(s, quote) { if (s.next_sell_price) return n(s.next_sell_price).format(s.product.increment, Math.ceil) else return n(quote.ask).add(n(quote.ask).multiply(s.options.markup_sell_pct / 100)).format(s.product.increment, Math.ceil) } function updatePeriod(trade) { s.period.high = Math.max(trade.price, s.period.high) s.period.low = Math.min(trade.price, s.period.low) s.period.close = trade.price s.period.volume += trade.size s.period.latest_trade_time = trade.time s.strategy.calculate(s) s.vol_since_last_blink += trade.size if (s.trades && s.last_trade_id !== trade.trade_id) { s.trades.push(trade) s.last_trade_id = trade.trade_id } } function executeStop (do_sell_stop) { let stop_signal if (s.my_trades.length || s.my_prev_trades.length) { var last_trade if (s.my_trades.length) { last_trade = s.my_trades[s.my_trades.length - 1] } else { last_trade = s.my_prev_trades[s.my_prev_trades.length - 1] } s.last_trade_worth = last_trade.type === 'buy' ? (s.period.close - last_trade.price) / last_trade.price : (last_trade.price - s.period.close) / last_trade.price if (!s.acted_on_stop) { if (last_trade.type === 'buy') { if (do_sell_stop && s.sell_stop && s.period.close < s.sell_stop) { stop_signal = 'sell' console.log(('\nsell stop triggered at ' + formatPercent(s.last_trade_worth) + ' trade worth\n').red) s.stopTriggered = true } else if (so.profit_stop_enable_pct && s.last_trade_worth >= (so.profit_stop_enable_pct / 100)) { s.profit_stop_high = Math.max(s.profit_stop_high || s.period.close, s.period.close) s.profit_stop = s.profit_stop_high - (s.profit_stop_high * (so.profit_stop_pct / 100)) } if (s.profit_stop && s.period.close < s.profit_stop && s.last_trade_worth > 0) { stop_signal = 'sell' console.log(('\nprofit stop triggered at ' + formatPercent(s.last_trade_worth) + ' trade worth\n').green) } } else { if (s.buy_stop && s.period.close > s.buy_stop) { stop_signal = 'buy' console.log(('\nbuy stop triggered at ' + formatPercent(s.last_trade_worth) + ' trade worth\n').red) } } } } if (stop_signal) { if(so.reverse) { s.signal = (stop_signal == 'sell') ? 'buy' : 'sell' s.acted_on_stop = true } else { s.signal = stop_signal s.acted_on_stop = true } } } function syncBalance (cb) { let pre_asset = so.mode === 'sim' ? s.sim_asset : s.balance.asset s.exchange.getBalance({currency: s.currency, asset: s.asset}, function (err, balance) { if (err) return cb(err) let diff_asset = n(pre_asset).subtract(balance.asset) s.balance = balance getQuote(function (err, quote) { if (err) return cb(err) let post_currency = n(diff_asset).multiply(quote.ask) s.asset_capital = n(s.balance.asset).multiply(quote.ask).value() let deposit = so.deposit ? Math.max(0, n(so.deposit).subtract(s.asset_capital)) : s.balance.currency // zero on negative s.balance.deposit = n(deposit < s.balance.currency ? deposit : s.balance.currency).value() if (!s.start_capital) { s.start_price = n(quote.ask).value() s.start_capital = n(s.balance.deposit).add(s.asset_capital).value() s.real_capital = n(s.balance.currency).add(s.asset_capital).value() s.net_currency = s.balance.deposit if (so.mode !== 'sim') { pushMessage('Balance ' + s.exchange.name.toUpperCase(), 'sync balance ' + s.real_capital + ' ' + s.currency + '\n') } } else { s.net_currency = n(s.net_currency).add(post_currency).value() } cb(null, { balance, quote }) }) }) } function placeOrder (type, opts, cb) { if (!s[type + '_order']) { s[type + '_order'] = { price: opts.price, size: opts.size, fee: opts.fee, orig_size: opts.size, remaining_size: opts.size, orig_price: opts.price, order_type: opts.is_taker ? 'taker' : so.order_type, cancel_after: so.cancel_after || 'day' } } let order = s[type + '_order'] order.price = opts.price order.size = opts.size order.fee = opts.fee order.remaining_size = opts.size if (isNaN(order.size) || isNaN(order.price) || isNaN(order.fee)) { // treat as a no-op. debug.msg('invalid order for ' + type + ', aborting') return cb(null, false) } order.product_id = s.product_id order.post_only = conf.post_only debug.msg('placing ' + type + ' order...') let order_copy = JSON.parse(JSON.stringify(order)) s.exchange[type](order_copy, function (err, api_order) { if (err) return cb(err) s.api_order = api_order if (api_order.status === 'rejected') { if (api_order.reject_reason === 'post only') { // trigger immediate price adjustment and re-order debug.msg('post-only ' + type + ' failed, re-ordering') return cb(null, null) } else if (api_order.reject_reason === 'balance') { // treat as a no-op. debug.msg('not enough balance for ' + type + ', aborting') return cb(null, false) } else if (api_order.reject_reason === 'price') { // treat as a no-op. debug.msg('invalid price for ' + type + ', aborting') return cb(null, false) } err = new Error('\norder rejected') err.order = api_order return cb(err) } debug.msg(type + ' order placed at ' + formatCurrency(order.price, s.currency)) order.order_id = api_order.id if (!order.time) { order.orig_time = new Date(api_order.created_at).getTime() } order.time = new Date(api_order.created_at).getTime() order.local_time = now() order.status = api_order.status //console.log('\ncreated ' + order.status + ' ' + type + ' order: ' + formatAsset(order.size) + ' at ' + formatCurrency(order.price) + ' (total ' + formatCurrency(n(order.price).multiply(order.size)) + ')\n') setTimeout(function() { checkOrder(order, type, cb) }, so.order_poll_time) }) } function getQuote (cb) { s.exchange.getQuote({product_id: s.product_id}, function (err, quote) { if (err) return cb(err) s.quote = quote cb(null, quote) }) } function isOrderTooSmall(product, quantity, price) { if (product.min_size && Number(quantity) < Number(product.min_size)) return true if (product.min_total && n(quantity).multiply(price).value() < Number(product.min_total)) return true return false } // if s.signal // 1. sync balance // 2. get quote // 3. calculate size/price // 4. validate size against min/max sizes // 5. cancel old orders // 6. place new order // 7. record order ID and start poll timer // 8. if not filled after timer, repeat process // 9. if filled, record order stats function executeSignal (signal, _cb, size, is_reorder, is_taker, reverseCalled) { if(so.reverse && !reverseCalled && !size && !is_reorder) { console.log(('\nREVERSE SIGNAL MODE ON!\n').red) return executeSignal(signal == 'buy' ? 'sell' : 'buy', _cb, size, is_reorder, is_taker, true) } let price, expected_fee, buy_pct, sell_pct, trades delete s[(signal === 'buy' ? 'sell' : 'buy') + '_order'] s.last_signal = signal if (!is_reorder && s[signal + '_order']) { if (is_taker) s[signal + '_order'].order_type = 'taker' // order already placed _cb && _cb(null, null) return } s.acted_on_trend = true let cb = function (err, order) { if (!order) { if (signal === 'buy') delete s.buy_order else delete s.sell_order } if (_cb) _cb(err, order) else if (err) { if (err.message.match(nice_errors)) { console.error((err.message + ': ' + err.desc).red) } else { memDump() console.error('\n') console.error(err) console.error('\n') } } } syncBalance(function (err, { quote }) { let reorder_pct, fee, trade_balance, tradeable_balance, expected_fee if (err) { debug.msg('error getting balance') err.desc = 'could not execute ' + signal + ': error fetching quote' return cb(err) } if (is_reorder && s[signal + '_order']) { if (signal === 'buy') { reorder_pct = n(size).multiply(s.buy_order.price).add(s.buy_order.fee).divide(s.balance.deposit).multiply(100) } else { reorder_pct = n(size).divide(s.balance.asset).multiply(100) } debug.msg('price changed, resizing order, ' + reorder_pct + '% remain') size = null } if (s.my_prev_trades.length) { trades = _.concat(s.my_prev_trades, s.my_trades) } else { trades = _.cloneDeep(s.my_trades) } if (signal === 'buy') { price = nextBuyForQuote(s, quote) if (is_reorder) { buy_pct = reorder_pct } else { buy_pct = so.buy_pct } if (so.use_fee_asset) { fee = 0 } else if (so.order_type === 'maker' && (buy_pct + s.exchange.takerFee < 100 || !s.exchange.makerBuy100Workaround)) { fee = s.exchange.makerFee } else { fee = s.exchange.takerFee } trade_balance = n(s.balance.deposit).divide(100).multiply(buy_pct) tradeable_balance = n(s.balance.deposit).divide(100 + fee).multiply(buy_pct) expected_fee = n(trade_balance).subtract(tradeable_balance).format('0.00000000', Math.ceil) // round up as the exchange will too if (buy_pct + fee < 100) { size = n(tradeable_balance).divide(price).format(s.product.asset_increment ? s.product.asset_increment : '0.00000000') } else { size = n(trade_balance).subtract(expected_fee).divide(price).format(s.product.asset_increment ? s.product.asset_increment : '0.00000000') } if (isOrderTooSmall(s.product, size, price)) return cb(null, null) if (s.product.max_size && Number(size) > Number(s.product.max_size)) { size = s.product.max_size } debug.msg('preparing buy order over ' + formatAsset(size, s.asset) + ' of ' + formatCurrency(tradeable_balance, s.currency) + ' (' + buy_pct + '%) tradeable balance with a expected fee of ' + formatCurrency(expected_fee, s.currency) + ' (' + fee + '%)') if (so.quarentine_time > 0 && s.buy_quarentine_time && moment.duration(moment(now()).diff(s.buy_quarentine_time)).asMinutes() < so.quarentine_time){ console.log(('\nbuy cancel quarentine time: '+moment(s.buy_quarentine_time).format('YYYY-MM-DD HH:mm:ss')).red) return cb(null, null) } let latest_low_sell = _.chain(trades).dropRightWhile(['type','buy']).takeRightWhile(['type','sell']).sortBy(['price']).head().value() // return lowest price let buy_loss = latest_low_sell ? (latest_low_sell.price - Number(price)) / latest_low_sell.price * -100 : null if (so.max_buy_loss_pct != null && buy_loss > so.max_buy_loss_pct) { let err = new Error('\nloss protection') err.desc = 'refusing to buy at ' + formatCurrency(price, s.currency) + ', buy loss of ' + formatPercent(buy_loss / 100) return cb(err) } if (s.buy_order && so.max_slippage_pct != null) { let slippage = n(price).subtract(s.buy_order.orig_price).divide(s.buy_order.orig_price).multiply(100).value() if (so.max_slippage_pct != null && slippage > so.max_slippage_pct) { let err = new Error('\nslippage protection') err.desc = 'refusing to buy at ' + formatCurrency(price, s.currency) + ', slippage of ' + formatPercent(slippage / 100) return cb(err) } } if (n(s.balance.deposit).subtract(s.balance.currency_hold || 0).value() < n(price).multiply(size).value() && s.balance.currency_hold > 0) { debug.msg('buy delayed: ' + formatPercent(n(s.balance.currency_hold || 0).divide(s.balance.deposit).value()) + ' of funds (' + formatCurrency(s.balance.currency_hold, s.currency) + ') on hold') return setTimeout(function () { if (s.last_signal === signal) { executeSignal(signal, cb, size, true) } }, conf.wait_for_settlement) } if(conf.notifiers && !conf.notifiers.only_completed_trades){ pushMessage('Buying ' + formatAsset(size, s.asset) + ' on ' + s.exchange.name.toUpperCase(), 'placing buy order at ' + formatCurrency(price, s.currency) + ', ' + formatCurrency(quote.bid - Number(price), s.currency) + ' under best bid\n') } doOrder() } else if (signal === 'sell') { price = nextSellForQuote(s, quote) if (is_reorder) { sell_pct = reorder_pct } else { sell_pct = so.sell_pct } size = n(s.balance.asset).multiply(sell_pct / 100).format(s.product.asset_increment ? s.product.asset_increment : '0.00000000') if (isOrderTooSmall(s.product, size, price)) return cb(null, null) if (s.product.max_size && Number(size) > Number(s.product.max_size)) { size = s.product.max_size } let latest_high_buy = _.chain(trades).dropRightWhile(['type','sell']).takeRightWhile(['type','buy']).sortBy(['price']).reverse().head().value() // return highest price let sell_loss = latest_high_buy ? (Number(price) - latest_high_buy.price) / latest_high_buy.price * -100 : null if (latest_high_buy && so.sell_cancel_pct != null && Math.abs(sell_loss) < so.sell_cancel_pct) { console.log(('\nsell_cancel_pct: refusing to sell at ' + formatCurrency(latest_high_buy.price, s.currency) + '-' + formatCurrency(price, s.currency) + ', sell loss of ' + formatPercent(sell_loss/100) + ' - ' + formatPercent(so.sell_cancel_pct/100)+'\n').red) return cb(null, null) } if (so.max_sell_loss_pct != null && sell_loss > so.max_sell_loss_pct) { let err = new Error('\nloss protection') err.desc = 'refusing to sell at ' + formatCurrency(price, s.currency) + ', sell loss of ' + formatPercent(sell_loss / 100) return cb(err) } if (s.sell_order && so.max_slippage_pct != null) { let slippage = n(s.sell_order.orig_price).subtract(price).divide(price).multiply(100).value() if (slippage > so.max_slippage_pct) { let err = new Error('\nslippage protection') err.desc = 'refusing to sell at ' + formatCurrency(price, s.currency) + ', slippage of ' + formatPercent(slippage / 100) return cb(err) } } if (n(s.balance.asset).subtract(s.balance.asset_hold || 0).value() < n(size).value()) { debug.msg('sell delayed: ' + formatPercent(n(s.balance.asset_hold || 0).divide(s.balance.asset).value()) + ' of funds (' + formatAsset(s.balance.asset_hold, s.asset) + ') on hold') return setTimeout(function () { if (s.last_signal === signal) { executeSignal(signal, cb, size, true) } }, conf.wait_for_settlement) } if(conf.notifiers && !conf.notifiers.only_completed_trades){ pushMessage('Selling ' + formatAsset(size, s.asset) + ' on ' + s.exchange.name.toUpperCase(), 'placing sell order at ' + formatCurrency(price, s.currency) + ', ' + formatCurrency(Number(price) - quote.bid, s.currency) + ' over best ask\n') } doOrder() } }) function doOrder () { placeOrder(signal, { size: size, price: price, fee: expected_fee || null, is_taker: is_taker, cancel_after: so.cancel_after || 'day' }, function (err, order) { if (err) { err.desc = 'could not execute ' + signal + ': error placing order' return cb(err) } if (!order) { if (order === false) { // not enough balance, or signal switched. debug.msg('not enough balance, or signal switched, cancel ' + signal) return cb(null, null) } if (s.last_signal !== signal) { // order timed out but a new signal is taking its place debug.msg('signal switched, cancel ' + signal) return cb(null, null) } // order timed out and needs adjusting debug.msg(signal + ' order timed out, adjusting price') let remaining_size = s[signal + '_order'] ? s[signal + '_order'].remaining_size : size if (remaining_size !== size) { debug.msg('remaining size: ' + remaining_size) } return executeSignal(signal, _cb, remaining_size, true) } cb(null, order) }) } } // Called after an order has been completed. // trade_type is either 'buy' or 'sell' function executeOrder (order, trade_type) { let order_type = so.order_type || 'maker' // "maker" or "taker" let price = order.price let fee = 0 let percentage_fee = 0 if (order_type === 'maker' && s.exchange.makerFee) percentage_fee = s.exchange.makerFee else if (order_type === 'taker' && s.exchange.takerFee) percentage_fee = s.exchange.takerFee if (trade_type === 'sell') fee = n(order.size).multiply(percentage_fee / 100).multiply(price).value() else if (trade_type === 'buy') fee = n(order.size).multiply(percentage_fee / 100).value() s.action = trade_type === 'sell' ? 'sold' : 'bought' // Compute profit from the last order price. let last_price_type = `last_${trade_type}_price` let previous_orders = s.my_prev_trades.filter(trade => trade.type === trade_type) if (!s[last_price_type] && previous_orders.length) { let last_price = previous_orders[previous_orders.length -1].price s[last_price_type] = last_price } let profit = s[last_price_type] && (s[last_price_type] - price) / s[last_price_type] s[last_price_type] = price let my_trade = { order_id: order.order_id, time: order.time, execution_time: order.time - order.orig_time, slippage: trade_type === 'sell' ? n(order.orig_price).subtract(price).divide(price).value() : n(price).subtract(order.orig_price).divide(order.orig_price).value(), type: trade_type, size: order.orig_size, fee: fee, price: price, order_type: order_type, profit: profit } if (trade_type === 'buy') my_trade.cancel_after = so.cancel_after || 'day' s.my_trades.push(my_trade) if (so.stats) { let execution_time = moment.duration(my_trade.execution_time).humanize() let completion_time = moment(order.time).format('YYYY-MM-DD HH:mm:ss') let asset_qty = formatAsset(my_trade.size, s.asset) let currency_price = formatCurrency(my_trade.price, s.currency) let total_price = formatCurrency(my_trade.size * my_trade.price, s.currency) let slippage = n(my_trade.slippage).format('0.0000%') let orig_price = formatCurrency(order.orig_price, s.currency) let order_complete = `\n${trade_type} order completed at ${completion_time}:\n\n` + `${asset_qty} at ${currency_price}\n` + `total ${total_price}\n` + `${slippage} slippage (orig. price ${orig_price})\n` + `execution: ${execution_time}\n` console.log((order_complete).cyan) pushMessage(`${trade_type} ${s.exchange.name.toUpperCase()}`, order_complete) } if(trade_type == 'sell' && !isNaN(profit) && profit <= 0) { s.buy_quarentine_time = now() } if (trade_type === 'buy') delete s.buy_order else delete s.sell_order delete s.buy_stop delete s.sell_stop if (trade_type === 'buy' && so.sell_stop_pct) { s.sell_stop = n(price).subtract(n(price).multiply(so.sell_stop_pct / 100)).value() } else if (trade_type === 'sell' && so.buy_stop_pct) { s.buy_stop = n(price).add(n(price).multiply(so.buy_stop_pct / 100)).value() } delete s.profit_stop delete s.profit_stop_high eventBus.emit('orderExecuted', trade_type) } function now () { return new Date().getTime() } function writeReport (is_progress, blink_off) { if ((so.mode === 'sim' || so.mode === 'train') && !so.verbose) { if(so.silent) return is_progress = true } else if (is_progress && typeof blink_off === 'undefined' && s.vol_since_last_blink) { s.vol_since_last_blink = 0 setTimeout(function () { writeReport(true, true) }, 200) setTimeout(function () { writeReport(true, false) }, 400) setTimeout(function () { writeReport(true, true) }, 600) setTimeout(function () { writeReport(true, false) }, 800) } readline.clearLine(process.stdout) readline.cursorTo(process.stdout, 0) process.stdout.write(moment(is_progress ? s.period.latest_trade_time : tb(s.period.time).resize(so.period_length).add(1).toMilliseconds()).format('YYYY-MM-DD HH:mm:ss')[is_progress && !blink_off ? 'bgBlue' : 'grey']) process.stdout.write(' ' + formatCurrency(s.period.close, s.currency, true, true, true) + ' ' + s.product_id.grey) if (s.lookback[0]) { let diff = (s.period.close - s.lookback[0].close) / s.lookback[0].close process.stdout.write(z(8, formatPercent(diff), ' ')[diff >= 0 ? 'green' : 'red']) } else { process.stdout.write(z(9, '', ' ')) } let volume_display = s.period.volume > 99999 ? abbreviate(s.period.volume, 2) : n(s.period.volume).format('0') volume_display = z(8, volume_display, ' ') if (volume_display.indexOf('.') === -1) volume_display = ' ' + volume_display process.stdout.write(volume_display[is_progress && blink_off ? 'cyan' : 'grey']) rsi(s, 'rsi', so.rsi_periods) if (typeof s.period.rsi === 'number') { let half = 5 let bar = '' let stars = 0 let rsi = n(s.period.rsi).format('00.00') if (s.period.rsi >= 50) { stars = Math.min(Math.round(((s.period.rsi - 50) / 50) * half) + 1, half) bar += ' '.repeat(half - (rsi < 100 ? 3 : 4)) bar += rsi.green + ' ' bar += '+'.repeat(stars).green.bgGreen bar += ' '.repeat(half - stars) } else { stars = Math.min(Math.round(((50 - s.period.rsi) / 50) * half) + 1, half) bar += ' '.repeat(half - stars) bar += '-'.repeat(stars).red.bgRed bar += rsi.length > 1 ? ' ' : ' ' bar += rsi.red bar += ' '.repeat(half - 3) } process.stdout.write(' ' + bar) } else { process.stdout.write(' '.repeat(11)) } if (s.strategy.onReport) { let cols = s.strategy.onReport.call(s.ctx, s) cols.forEach(function (col) { process.stdout.write(col) }) } if (s.buy_order) { process.stdout.write(z(9, 'buying', ' ').green) } else if (s.sell_order) { process.stdout.write(z(9, 'selling', ' ').red) } else if (s.action) { process.stdout.write(z(9, s.action, ' ')[s.action === 'bought' ? 'green' : 'red']) } else if (s.signal) { process.stdout.write(z(9, s.signal || '', ' ')[s.signal ? s.signal === 'buy' ? 'green' : 'red' : 'grey']) } else if (s.last_trade_worth && !s.buy_order && !s.sell_order) { process.stdout.write(z(8, formatPercent(s.last_trade_worth), ' ')[s.last_trade_worth > 0 ? 'green' : 'red']) } else { process.stdout.write(z(9, '', ' ')) } let orig_capital = s.orig_capital || s.start_capital let orig_price = s.orig_price || s.start_price if (orig_capital) { let asset_col = n(s.balance.asset).format(s.asset === 'BTC' ? '0.00000' : '0.00000000') + ' ' + s.asset asset_col_width = Math.max(asset_col.length + 1, asset_col_width) process.stdout.write(z(asset_col_width, asset_col, ' ').white) let deposit_col = n(s.balance.deposit).format(isFiat() ? '0.00' : '0.00000000') + ' ' + s.currency deposit_col_width = Math.max(deposit_col.length + 1, deposit_col_width) process.stdout.write(z(deposit_col_width, deposit_col, ' ').yellow) if (so.deposit) { let currency_col = n(s.balance.currency).format(isFiat() ? '0.00' : '0.00000000') + ' ' + s.currency currency_col_width = Math.max(currency_col.length + 1, currency_col_width) process.stdout.write(z(currency_col_width, currency_col, ' ').green) let circulating = s.balance.currency > 0 ? n(s.balance.deposit).divide(s.balance.currency) : n(0) process.stdout.write(z(8, n(circulating).format('0.00%'), ' ').grey) } let consolidated = n(s.net_currency).add(n(s.balance.asset).multiply(s.period.close)) let profit = n(consolidated).divide(orig_capital).subtract(1).value() process.stdout.write(z(8, formatPercent(profit), ' ')[profit >= 0 ? 'green' : 'red']) let buy_hold = n(orig_capital).divide(orig_price).multiply(s.period.close) let over_buy_hold_pct = n(consolidated).divide(buy_hold).subtract(1).value() process.stdout.write(z(8, formatPercent(over_buy_hold_pct), ' ')[over_buy_hold_pct >= 0 ? 'green' : 'red']) } if (!is_progress) { process.stdout.write('\n') } } function withOnPeriod (trade, period_id, cb) { if (!clock && so.mode !== 'live' && so.mode !== 'paper') clock = lolex.install({ shouldAdvanceTime: false, now: trade.time }) updatePeriod(trade) if (!s.in_preroll) { if (so.mode !== 'live') s.exchange.processTrade(trade) if (!so.manual) { executeStop() if (clock) { var diff = trade.time - now() // Allow some catch-up if trades are too far apart. Don't want all calls happening at the same time while (diff > 5000) { clock.tick(5000) diff -= 5000 } clock.tick(diff) } if (s.signal) { executeSignal(s.signal) s.signal = null } } } s.last_period_id = period_id cb() } function cancelOrder (order, type, do_reorder, cb) { s.exchange.cancelOrder({order_id: order.order_id, product_id: s.product_id}, function () { function checkHold (do_reorder, cb) { s.exchange.getOrder({order_id: order.order_id, product_id: s.product_id}, function (err, api_order) { if (api_order) { if (api_order.status === 'done') { order.time = new Date(api_order.done_at).getTime() order.price = api_order.price || order.price // Use actual price if possible. In market order the actual price (api_order.price) could be very different from trade price debug.msg('cancel failed, order done, executing') executeOrder(order, type) return syncBalance(function () { cb(null, order) }) } s.api_order = api_order if (api_order.filled_size) { order.remaining_size = n(order.size).subtract(api_order.filled_size).format(s.product.asset_increment ? s.product.asset_increment : '0.00000000') } } syncBalance(function () { let on_hold if (type === 'buy') on_hold = n(s.balance.deposit).subtract(s.balance.currency_hold || 0).value() < n(order.price).multiply(order.remaining_size).value() else on_hold = n(s.balance.asset).subtract(s.balance.asset_hold || 0).value() < n(order.remaining_size).value() if (on_hold && s.balance.currency_hold > 0) { // wait a bit for settlement debug.msg('funds on hold after cancel, waiting 5s') setTimeout(function() { checkHold(do_reorder, cb) }, conf.wait_for_settlement) } else { cb(null, do_reorder ? null : false) } }) }) } checkHold(do_reorder, cb) }) } function checkOrder (order, type, cb) { if (!s[type + '_order']) { // signal switched, stop checking order debug.msg('signal switched during ' + type + ', aborting') return cancelOrder(order, type, false, cb) } s.exchange.getOrder({order_id: order.order_id, product_id: s.product_id}, function (err, api_order) { if (err) return cb(err) s.api_order = api_order order.status = api_order.status if (api_order.reject_reason) order.reject_reason = api_order.reject_reason if (api_order.status === 'done') { order.time = new Date(api_order.done_at).getTime() order.price = api_order.price || order.price // Use actual price if possible. In market order the actual price (api_order.price) could be very different from trade price executeOrder(order, type) return syncBalance(function () { cb(null, order) }) } if (order.status === 'rejected' && (order.reject_reason === 'post only' || api_order.reject_reason === 'post only')) { debug.msg('post-only ' + type + ' failed, re-ordering') return cb(null, null) } if (order.status === 'rejected' && order.reject_reason === 'balance') { debug.msg('not enough balance for ' + type + ', aborting') return cb(null, null) } if (now() - order.local_time >= so.order_adjust_time) { getQuote(function (err, quote) { if (err) { err.desc = 'could not execute ' + type + ': error fetching quote' return cb(err) } let marked_price if (type === 'buy') { marked_price = nextBuyForQuote(s, quote) if (so.exact_buy_orders && n(order.price).value() != marked_price) { debug.msg(marked_price + ' vs! our ' + order.price) cancelOrder(order, type, true, cb) } else if (n(order.price).value() < marked_price) { debug.msg(marked_price + ' vs our ' + order.price) cancelOrder(order, type, true, cb) } else { order.local_time = now() setTimeout(function() { checkOrder(order, type, cb) }, so.order_poll_time) } } else { marked_price = nextSellForQuote(s, quote) if (so.exact_sell_orders && n(order.price).value() != marked_price) { debug.msg(marked_price + ' vs! our ' + order.price) cancelOrder(order, type, true, cb) } else if (n(order.price).value() > marked_price) { debug.msg(marked_price + ' vs our ' + order.price) cancelOrder(order, type, true, cb) } else { order.local_time = now() setTimeout(function() { checkOrder(order, type, cb) }, so.order_poll_time) } } }) } else { setTimeout(function() { checkOrder(order, type, cb) }, so.order_poll_time) } }) } var tradeProcessingQueue = async.queue(function({trade, is_preroll}, callback){ onTrade(trade, is_preroll, callback) }) function queueTrade(trade, is_preroll){ tradeProcessingQueue.push({trade, is_preroll}) } function onTrade(trade, is_preroll, cb) { if (s.period && trade.time < s.period.time) { return cb() } var day = (new Date(trade.time)).getDate() if (s.last_day && day !== s.last_day) { s.day_count++ } s.last_day = day if (!s.period) { initBuffer(trade) } s.in_preroll = is_preroll || (so.start && trade.time < so.start) if (!s.period.last_try_trade && !s.in_preroll) { s.period.last_try_trade = now() } if(trade.time > s.period.close_time || (!s.in_preroll && so.mode != 'sim' && moment.duration(moment(now()).diff(s.period.last_try_trade)).asMinutes() >= so.interval_trade)){ var period_id = tb(trade.time).resize(so.period_length).toString() s.period.last_try_trade = now() s.strategy.onPeriod.call(s.ctx, s, function () { writeReport() s.acted_on_stop = false if (!s.in_preroll && !so.manual) { executeStop(true) if (s.signal) { executeSignal(s.signal) } } //s.action = null s.signal = null if (trade.time > s.period.close_time) { s.lookback.unshift(s.period) initBuffer(trade) } withOnPeriod(trade, period_id, cb) }) } else { withOnPeriod(trade, period_id, cb) } } function onTrades(trades, is_preroll, cb) { if (_.isFunction(is_preroll)) { cb = is_preroll is_preroll = false } trades.sort(function (a, b) { if (a.time < b.time) return -1 if (a.time > b.time) return 1 return 0 }) var local_trades = trades.slice(0) var trade while( (trade = local_trades.shift()) !== undefined ) { queueTrade(trade, is_preroll) } if(_.isFunction(cb)) cb() } return { writeHeader: function () { process.stdout.write([ z(19, 'DATE', ' ').grey, z(17, 'PRICE', ' ').grey, z(9, 'DIFF', ' ').grey, z(10, 'VOL', ' ').grey, z(8, 'RSI', ' ').grey, z(32, 'ACTIONS', ' ').grey, z(so.deposit ? 38 : 25, 'BAL', ' ').grey, z(22, 'PROFIT', ' ').grey ].join('') + '\n') }, update: onTrades, exit: function (cb) { if(tradeProcessingQueue.length()){ tradeProcessingQueue.drain(() => { if(s.strategy.onExit) { s.strategy.onExit.call( s.ctx, s ) } cb() }) } else { if(s.strategy.onExit) { s.strategy.onExit.call( s.ctx, s ) } cb() } }, executeSignal: executeSignal, writeReport: writeReport, syncBalance: syncBalance, pushMessage: pushMessage, onMessage: onMessage, } } ================================================ FILE: lib/format.js ================================================ let n = require('numbro') let max_fc_width = 0 module.exports = { formatAsset: function formatAsset (amt, asset) { return n(amt).format('0.00000000') + ' ' + asset }, formatPercent: function formatPercent (ratio) { return (ratio >= 0 ? '+' : '') + n(ratio).format('0.00%') }, formatCurrency: function formatCurrency (amt, currency, omit_currency, color_trick, do_pad) { let str let fstr amt > 999 ? fstr = '0.00' : amt > 99 ? fstr = '0.000' : amt > 9 ? fstr = '0.0000' : amt > 0.9 ? fstr = '0.00000' : amt > 0.09 ? fstr = '0.000000' : amt > 0.009 ? fstr = '0.0000000' : fstr = '0.00000000' str = n(amt).format(fstr) if (do_pad) { max_fc_width = Math.max(max_fc_width, str.length) str = ' '.repeat(max_fc_width - str.length) + str } if (color_trick) { str = str .replace(/^(.*\.)(.*?)(0*)$/, function (_, m1, m2, m3) { return m1.cyan + m2.yellow + m3.grey }) } return str + (omit_currency ? '' : ' ' + currency) } } ================================================ FILE: lib/heikinAshi.js ================================================ module.exports = function heikinAshi (s, key) { if (s.lookback.length > 0) { var prev = s.lookback[0] if (typeof prev !== 'undefined') { s.period[key] = { open: (prev.open + prev.close) / 2, high: Math.max(s.period.open, s.period.high, s.period.close), low: Math.min(s.period.open, s.period.low, s.period.close), close: (s.period.open + s.period.high + s.period.low + s.period.close) / 4, } } } } ================================================ FILE: lib/helpers.js ================================================ //Basic Usage // let crossover = require('../../../lib/helpers').crossover, // or // const tv = require('../../../lib/helpers') // ... // s.period.hl2 = tv.hl2(s.period) module.exports = { crossover: function(s, key1, key2) { return s.period[key1] > s.period[key2] && s.lookback[0][key1] <= s.lookback[0][key2] }, crossunder: function(s, key1, key2) { return s.period[key1] < s.period[key2] && s.lookback[0][key1] >= s.lookback[0][key2] }, crossoverVal: function(p1val1, p1val2, p2val1, p2val2) { return p1val1 > p1val2 && p2val1 <= p2val2 }, crossunderVal: function(p1val1, p1val2, p2val1, p2val2) { return p1val1 < p1val2 && p2val1 >= p2val2 }, nz: function(src, val = 0) { return typeof src != 'number' || isNaN(src) ? val : src }, iff: function(v, r, r2) { return v != undefined && v ? r : r2 }, hl2: function(period) { return (period.high + period.low) / 2 }, hlc3: function(period) { return (period.high + period.low + period.close) / 3 }, ohlc4: function(period) { return (period.open + period.high + period.low + period.close) / 4 }, HAhlc3: function(period, lookback) { /* xClose = (Open+High+Low+Close)/4 xOpen = [xOpen(Previous Bar) + xClose(Previous Bar)]/2 xHigh = Max(High, xOpen, xClose) xLow = Min(Low, xOpen, xClose) */ let haClose = (period.open + period.high + period.low + period.close) / 4, haClosePeriod = lookback != undefined ? lookback : period, haClosePrev = (haClosePeriod.open + haClosePeriod.high + haClosePeriod.low + haClosePeriod.close) / 4, haOpen = (period.haOpen ? period.haOpen : period.open + haClosePrev) / 2, haHigh = Math.max(period.high, haOpen, haClose), haLow = Math.min(period.low, haOpen, haClose) // save haOpen period.haOpen = haOpen return (haClose + haHigh + haLow) / 3 }, HAohlc4: function(period, lookback) { /* xClose = (Open+High+Low+Close)/4 xOpen = [xOpen(Previous Bar) + xClose(Previous Bar)]/2 xHigh = Max(High, xOpen, xClose) xLow = Min(Low, xOpen, xClose) */ let haClose = (period.open + period.high + period.low + period.close) / 4, haClosePeriod = lookback != undefined ? lookback : period, haClosePrev = (haClosePeriod.open + haClosePeriod.high + haClosePeriod.low + haClosePeriod.close) / 4, haOpen = (period.haOpen ? period.haOpen : period.open + haClosePrev) / 2, haHigh = Math.max(period.high, haOpen, haClose), haLow = Math.min(period.low, haOpen, haClose) // save haOpen period.haOpen = haOpen return (haClose + haOpen + haHigh + haLow) / 4 }, // sample usage: let adjusted_lbks = s.lookback.map((period, i) => tv.src(period, s.options.src, s.lookback[i+1])) src: function(src, period, lookback) { if (!period) throw 'helpers src(). period undefined' if (!src || src === 'close') { return period.close } else if (src === 'hl2') { return module.exports.hl2(period) } else if (src === 'hlc3') { return module.exports.hlc3(period) } else if (src === 'ohlc4') { return module.exports.ohlc4(period) } else if (src === 'HAhlc3') { return module.exports.HAhlc3(period, lookback) } else if (src === 'HAohlc4') { return module.exports.HAohlc4(period, lookback) } else throw src + ' not supported' }, adjust_by_pct: function(pct, n) { return n * (pct / 100 + 1) }, pivot: function(s, leftBars, rightBars) { let totalBars = leftBars + rightBars + 1, periods = [s.period, ...s.lookback.slice(0, totalBars - 1)].reverse(), lPeriods = periods.slice(0, leftBars), rPeriods = periods.slice(leftBars + 1), oPeriods = lPeriods.concat(rPeriods), countH = oPeriods.reduce((p, c) => { return p + (typeof c.high !== 'undefined' && periods[leftBars].high > c.high ? 1 : 0) }, 0), countL = oPeriods.reduce((p, c) => { return p + (typeof c.low !== 'undefined' && periods[leftBars].low < c.low ? 1 : 0) }, 0) return { high: countH == oPeriods.length ? periods[leftBars].high : null, low: countL == oPeriods.length ? periods[leftBars].low : null } } } ================================================ FILE: lib/highest.js ================================================ module.exports = function highest(s, key, length) { if (s.lookback.length < length) { s.period[key] = 0 } else { s.period[key] = s.period[key] = Math.max(s.period.high, ...s.lookback.slice(0, length - 1).map(period => period.high)) } } ================================================ FILE: lib/kc.js ================================================ // Keltner Channels var keltnerchannel = require('keltnerchannel').kc module.exports = function kc (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length > length) { let data = [] for (var i=length-1; i>=0; i--) { data.push({ high: s.lookback[i].high, low: s.lookback[i].low, close: s.lookback[i].close }) } let result = keltnerchannel(data, s.options.kc_size, s.options.kc_multiplier) s.period[key] = result } } ================================================ FILE: lib/lowest.js ================================================ module.exports = function lowest(s, key, length) { if (s.lookback.length < length) { s.period[key] = 0 } else { s.period[key] = s.period[key] = Math.min(s.period.low, ...s.lookback.slice(0, length - 1).map(period => period.low)) } } ================================================ FILE: lib/lrc.js ================================================ // Linear Regression Curve var regression = require('regression') module.exports = function lrc (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length > length) { let data = [] for (var i=length-1; i>=0; i--) { data.push([length-1-i, s.lookback[i][source_key]]) } let result = regression.linear(data) s.period[key] = result.equation[1] + result.equation[0]*(length-1) } } ================================================ FILE: lib/momentum.js ================================================ module.exports = function momentum(s, key, source_key, length) { if (s.lookback == null || s.lookback.length < length || s.period == null || s.period[source_key] == null) { s.period[key] = 0 } else { s.period[key] = s.period[source_key] - s.lookback[length - 1][source_key] } } ================================================ FILE: lib/normalize-selector.js ================================================ module.exports = function (selector) { var parts = selector.split('.') return parts[0].toLowerCase() + '.' + (parts[1] || '').toUpperCase() } ================================================ FILE: lib/notify.js ================================================ module.exports = function notifier (conf) { var active_notifiers = [] var interactive_notifiers = [] for (var notifier in conf.notifiers) { if (conf.notifiers[notifier].on) { var notif = require(`../extensions/notifiers/${notifier}`)(conf.notifiers[notifier]) notif.notifier_name = notifier active_notifiers.push(notif) if (conf.notifiers[notifier].interactive) { interactive_notifiers.push(notif) } } } return { pushMessage: function (title, message) { if (conf.debug) { console.log(`${title}: ${message}`) } active_notifiers.forEach((notifier) => { if (conf.debug) { console.log(`Sending push message via ${notifier.notifier_name}`) } notifier.pushMessage(title, message) }) }, onMessage: function (callback) { interactive_notifiers.forEach((notifier) => { if (conf.debug) { console.log(`Receiving message from ${notifier.notifier_name}`) } notifier.onMessage(callback) }) } } } ================================================ FILE: lib/objectify-selector.js ================================================ var normalizeSelector = require('./normalize-selector') module.exports = function(selector) { var rtn if (typeof selector == 'string') { var s = normalizeSelector(selector) var e_id = s.split('.')[0] var p_id = s.split('.')[1] var asset = p_id.split('-')[0] var currency = p_id.split('-')[1] rtn = {exchange_id: e_id, product_id: p_id, asset: asset, currency: currency, normalized: s} } else if (typeof selector == 'object') { rtn = selector } return rtn } ================================================ FILE: lib/output.js ================================================ var path = require('path') module.exports = function output (conf) { var initializeOutput = function(tradeObject) { for (var output in conf.output) { if (conf.output[output].on) { if (conf.debug) { console.log(`initializing output ${output}`) } require(path.resolve(__dirname, `../extensions/output/${output}`))(conf).run(conf.output[output], tradeObject) } } } return { initializeOutput: initializeOutput } } ================================================ FILE: lib/phenotype.js ================================================ /* * Zenbot 4 Genetic Backtester * Clifford Roche * 07/01/2017 */ let PROPERTY_RANDOM_CHANCE = 0.30 // Chance of a Mutation to spawn a new species -- Try and prevent some stagnation let PROPERTY_MUTATION_CHANCE = 0.30 // Chance of a Mutation in an aspect of the species let PROPERTY_CROSSOVER_CHANCE = 0.50 // Chance of a aspect being inherited by another species module.exports = { create: function(strategy) { var r = {} for (var k in strategy) { var v = strategy[k] if (v.type === 'int') { r[k] = Math.floor((Math.random() * (v.max - v.min + 1)) + v.min) } else if (v.type === 'int0') { r[k] = 0 if (Math.random() >= 0.5) { r[k] = Math.floor((Math.random() * (v.max - v.min + 1)) + v.min) } } else if (v.type === 'intfactor') { let factorString = v.factor.toString(), decimalIdx = factorString.indexOf('.') + 1, decimals = decimalIdx === 0 ? 0 : factorString.length - decimalIdx r[k] = (Math.floor(Math.random() * (v.max - v.min + v.factor) / v.factor) * v.factor + v.min).toFixed(decimals) } else if (v.type === 'float') { r[k] = (Math.random() * (v.max - v.min)) + v.min } else if (v.type === 'period_length') { var s = Math.floor((Math.random() * (v.max - v.min + 1)) + v.min) r[k] = s + v.period_length } else if (v.type === 'listOption') { let index = Math.floor(Math.random() * v.options.length) r[k] = v.options[index] } else if (v.type === 'maType') { let items = ['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA', 'KAMA', 'MAMA', 'T3'] let index = Math.floor(Math.random() * items.length) r[k] = items[index] } else if (v.type === 'uscSignalType') { let items = ['simple', 'low', 'trend'] let index = Math.floor(Math.random() * items.length) r[k] = items[index] } } return r }, range: function(v, step, stepSize) { var scale = step / (stepSize - 1) if (v.type === 'int') { return Math.floor((scale * (v.max - v.min)) + v.min) } else if (v.type === 'int0') { if (step == 0) return 0 scale = (step - 1) / (stepSize - 2) return Math.floor((scale * (v.max - v.min)) + v.min) } else if (v.type === 'intfactor') { let val = Math.floor((scale * (v.max - v.min)) + v.min) return Math.floor(val / v.factor) * v.factor } else if (v.type === 'float') { return (scale * (v.max - v.min)) + v.min } else if (v.type === 'period_length') { var s = Math.floor((scale * (v.max - v.min)) + v.min) return s + v.period_length } else if (v.type === 'listOption') { scale = step / stepSize let index = Math.floor(scale * v.options.length) return v.options[index] } }, mutation: function(oldPhenotype, strategy) { var r = module.exports.create(strategy) if(Math.random() > PROPERTY_RANDOM_CHANCE) { for (var k in oldPhenotype) { if (k === 'sim') continue var v = oldPhenotype[k] r[k] = (Math.random() < PROPERTY_MUTATION_CHANCE) ? r[k] : v } } return r }, crossover: function(phenotypeA, phenotypeB, strategy) { var p1 = {} var p2 = {} for (var k in strategy) { if (k === 'sim') continue if (k === 'minTrades') continue if (k === 'fitnessCalcType') continue p1[k] = Math.random() <= PROPERTY_CROSSOVER_CHANCE ? phenotypeA[k] : phenotypeB[k] p2[k] = Math.random() <= PROPERTY_CROSSOVER_CHANCE ? phenotypeA[k] : phenotypeB[k] } return [p1, p2] }, fitness: function(phenotype) { if (typeof phenotype.sim === 'undefined') return 0 let rate = 0 if (phenotype.fitnessCalcType == 'profitwl') { let profit = phenotype.sim.profit + (phenotype.sim.assetCapital * phenotype.sim.lastAssestValue) // if minTrades is set use an alternate fitness calculation to hone in on a trade stratagy that has the minimum trade count // once found use the normal fitness strsategy to find the best parameters. if (phenotype.minTrades > 0) { if (phenotype.sim.wins < phenotype.minTrades && phenotype.sim.wins == 0) return 0.0 if (phenotype.sim.wins < phenotype.minTrades) return ((phenotype.sim.wins/phenotype.minTrades)+profit)/100 } let wlRatio = phenotype.sim.wins / phenotype.sim.losses if (isNaN(wlRatio)) { // zero trades will result in 0/0 which is NaN wlRatio = 0 } let wlRatioRate = 1.0 / (1.0 + Math.pow(Math.E,-wlRatio)) rate = (profit * wlRatioRate ) } else if (phenotype.fitnessCalcType == 'profit') { //let profit = phenotype.sim.profit let profit = phenotype.sim.profit + (phenotype.sim.assetCapital * phenotype.sim.lastAssestValue) // if minTrades is set use an alternate fitness calculation to hone in on a trade stratagy that has the minimum trade count // once found use the normal fitness strsategy to find the best parameters. if (phenotype.minTrades > 0) { if (phenotype.sim.wins < phenotype.minTrades && phenotype.sim.wins == 0) return 0.0 if (phenotype.sim.wins < phenotype.minTrades) return ((phenotype.minTrades)+profit)/1000 } rate = profit } if (phenotype.fitnessCalcType == 'wl') { //let vsBuyHoldRate = phenotype.sim.profit // if minTrades is set use an alternate fitness calculation to hone in on a trade stratagy that has the minimum trade count // once found use the normal fitness strsategy to find the best parameters. if (phenotype.minTrades > 0) { if (phenotype.sim.wins < phenotype.minTrades && phenotype.sim.wins == 0) return 0.0 if (phenotype.sim.wins < phenotype.minTrades) return (phenotype.sim.wins/phenotype.minTrades)/100 } let wlRatio = phenotype.sim.wins / phenotype.sim.losses if (isNaN(wlRatio)) { // zero trades will result in 0/0 which is NaN wlRatio = 0 } let wlRatioRate = 1.0 / (1.0 + Math.pow(Math.E,-wlRatio)) rate = ( wlRatioRate ) } else { let vsBuyHoldRate = ((phenotype.sim.vsBuyHold + 100) / 50) if (phenotype.minTrades > 0) { if (phenotype.sim.wins < phenotype.minTrades && phenotype.sim.wins == 0) return 0.0 if (phenotype.sim.wins < phenotype.minTrades) return ((phenotype.sim.wins/phenotype.minTrades)+vsBuyHoldRate)/100 } let wlRatio = phenotype.sim.wins / phenotype.sim.losses if (isNaN(wlRatio)) { // zero trades will result in 0/0 which is NaN wlRatio = 1 } let wlRatioRate = 1.0 / (1.0 + Math.pow(Math.E, -wlRatio)) rate = vsBuyHoldRate * wlRatioRate } return rate }, competition: function(phenotypeA, phenotypeB) { // TODO: Refer to geneticalgorithm documentation on how to improve this with diverstiy return module.exports.fitness(phenotypeA) >= module.exports.fitness(phenotypeB) }, Range: function(min, max) { var r = { type: 'int', min: min, max: max } return r }, Range0: function(min, max) { var r = { type: 'int0', min: min, max: max } return r }, RangeFactor: function(min, max, factor) { var r = { type: 'intfactor', min: min, max: max, factor: factor } return r }, RangeFloat: function(min, max) { var r = { type: 'float', min: min, max: max } return r }, RangePeriod: function(min, max, period_length) { var r = { type: 'period_length', min: min, max: max, period_length: period_length } return r }, RangeMaType: function() { var r = { type: 'listOption', options: ['SMA', 'EMA', 'WMA', 'DEMA', 'TEMA', 'TRIMA', 'KAMA', 'MAMA', 'T3'] } return r }, ListOption: function(options) { var r = { type: 'listOption', options: options } return r } } ================================================ FILE: lib/rsi.js ================================================ var precisionRound = function(number, precision) { var factor = Math.pow(10, precision) return Math.round(number * factor) / factor } module.exports = function rsi (s, key, length) { if (s.lookback.length >= length) { var avg_gain = s.lookback[0][key + '_avg_gain'] var avg_loss = s.lookback[0][key + '_avg_loss'] if (typeof avg_gain === 'undefined') { var gain_sum = 0 var loss_sum = 0 var last_close s.lookback.slice(0, length).reverse().forEach(function (period) { if (last_close) { if (period.close > last_close) { gain_sum += period.close - last_close } else { loss_sum += last_close - period.close } } last_close = period.close }) s.period[key + '_avg_gain'] = gain_sum / length s.period[key + '_avg_loss'] = loss_sum / length } else { var current_gain = s.period.close - s.lookback[0].close s.period[key + '_avg_gain'] = ((avg_gain * (length - 1)) + (current_gain > 0 ? current_gain : 0)) / length var current_loss = s.lookback[0].close - s.period.close s.period[key + '_avg_loss'] = ((avg_loss * (length - 1)) + (current_loss > 0 ? current_loss : 0)) / length } if(s.period[key + '_avg_loss'] == 0) { s.period[key] = 100 } else { var rs = s.period[key + '_avg_gain'] / s.period[key + '_avg_loss'] s.period[key] = precisionRound(100 - (100 / (1 + rs)), 2) } } } ================================================ FILE: lib/sar.js ================================================ module.exports = function sar(s, key, initAccel, deltaAccel, accelMax) { if (s.lookback.length < 2) { return } // SAR# if (!s.lookback[0][key + '_sar#']) { s.period[key + '_sar#'] = -1 } else { if (s.lookback[0][key + '_sar#'] < 0) { if (s.period[key + '_tsar'] < s.period.high) s.period[key + '_sar#'] = 1 else s.period[key + '_sar#'] = s.lookback[0][key + '_sar#'] - 1 } else { if (s.period[key + '_tsar'] > s.period.low) s.period[key + '_sar#'] = -1 else s.period[key + '_sar#'] = s.lookback[0][key + '_sar#'] + 1 } } // EP if (s.period[key + '_sar#'] < 0) { if (s.period[key + '_sar#'] == -1) { s.period[key + '_ep'] = s.period.low } else { s.period[key + '_ep'] = Math.min(s.period.low, s.lookback[0][key + '_ep']) } } else { if (s.period[key + '_sar#'] == 1) { s.period[key + '_ep'] = s.period.high } else { s.period[key + '_ep'] = Math.max(s.period.high, s.lookback[0][key + '_ep']) } } // AF if (Math.abs(s.period[key + '_sar#']) == 1) { s.period[key + '_af'] = initAccel } else if (s.period[key + '_ep'] == s.lookback[0][key + '_ep']) { s.period[key + '_af'] = s.lookback[0][key + '_af'] } else { s.period[key + '_af'] = Math.min(accelMax, deltaAccel + s.lookback[0][key + '_af']) } // tentative sar if (s.lookback[0][key + '_sar#'] < 0) { s.period[key + '_tsar'] = Math.max(s.lookback[0][key] + s.lookback[0][key + '_af'] * (s.lookback[0][key + '_ep'] - s.lookback[0][key]), s.lookback[0].high, s.lookback[1].high) } else { s.period[key + '_tsar'] = Math.min(s.lookback[0][key] + s.lookback[0][key + '_af'] * (s.lookback[0][key + '_ep'] - s.lookback[0][key]), s.lookback[0].low, s.lookback[1].low) } // SAR if (!s.lookback[0][key]) { if (s.period[key + '_sar#'] < 0) { s.period[key] = s.lookback[0].high } else { s.period[key] = s.lookback[0].low } } else if (s.period[key + '_sar#'] == -1) { s.period[key] = Math.max(s.lookback[0][key + '_ep'], s.period.high) } else if (s.period[key + '_sar#'] == 1) { s.period[key] = Math.min(s.lookback[0][key + '_ep'], s.period.low) } else { s.period[key] = s.period[key + '_tsar'] } } ================================================ FILE: lib/services/collection-service.js ================================================ module.exports = function (conf) { return { getTrades: () => { conf.db.mongo.collection('trades').createIndex({selector: 1, time: 1}) return conf.db.mongo.collection('trades') }, getResumeMarkers: () => { conf.db.mongo.collection('resume_markers').createIndex({selector: 1, to: -1}) return conf.db.mongo.collection('resume_markers') }, getBalances: () => { return conf.db.mongo.collection('balances') }, getSessions: () => { return conf.db.mongo.collection('sessions') }, getPeriods: () => { return conf.db.mongo.collection('periods') }, getMyTrades: () => { return conf.db.mongo.collection('my_trades') }, getSimResults: () => { return conf.db.mongo.collection('sim_results') } } } ================================================ FILE: lib/services/consume-and-process-service.js ================================================ var events = require('events'), resumeMarkersService = require('./resume-marker-service') /** This service makes it easy do the the two step process of getting a bunch of resources, and then processing them. You supply a function which calls the API, calls the database, reads a file, a socket, whatever. When the records are retrieved, they are pushed into the supplied queue. You supply a function which dequeues the queue, and does something with the records. Somthing like calculating summary data, and/or storing them in a database. Both functions you supply can exit with a code that indicates they are done, at which point the consume-and-process process ends. **/ module.exports = function (conf) { var theService = {} var onConsumeFunc var onProcessFunc var afterOnConsumeFunc var afterOnProcessFunc var Queue = require('../_data-structures/Queue.js') var _emitter = new events.EventEmitter theService.setOnConsumeFunc = (func) => { onConsumeFunc = func } theService.setOnProcessFunc = (func) => { onProcessFunc = func } theService.setAfterOnConsumeFunc = (func) => { afterOnConsumeFunc = func } theService.setAfterOnProcessFunc = (func) => { afterOnProcessFunc = func } theService.go = (targetTimeInMillis) => { var rtn = new Promise((resolve/*, reject*/) => { var resumeMarkerService = resumeMarkersService(conf) _emitter = new events.EventEmitter var _queue = new Queue() _emitter.on('cp_consume', (record) => { onConsumeFunc(record, _queue, (err, rtnCode, mostRecentlyProcessedRecordId) => { if (rtnCode !== undefined) { if (afterOnConsumeFunc) afterOnConsumeFunc(mostRecentlyProcessedRecordId) _emitter.emit(rtnCode, mostRecentlyProcessedRecordId) } }) }) _emitter.on('cp_process', () => { onProcessFunc(targetTimeInMillis, _queue, resumeMarkerService.ping, (err, stopProcessingConditionReached, exitRecordId, data) => { if (afterOnProcessFunc) { data.pingCount = resumeMarkerService.getPingCount() afterOnProcessFunc(exitRecordId, data) } if (stopProcessingConditionReached) { setImmediate(() => { resumeMarkerService.flush(() => { _emitter.emit('cp_exit', exitRecordId) }) }) } else { setImmediate(() => { resumeMarkerService.flush(() => { _emitter.emit('cp_consume', exitRecordId) }) }) } }) }) _emitter.on('cp_exit', (mostRecentlyProcessedRecordId) => { resumeMarkerService.flush(() => { resolve(mostRecentlyProcessedRecordId) }) }) // Get things started resumeMarkerService.load(() => { _emitter.emit('cp_consume', undefined) }) }) return rtn } return theService } ================================================ FILE: lib/services/exchange-service.js ================================================ var objectifySelector = require('../objectify-selector') var path = require('path') module.exports = function (conf) { // ASSUMES c.selector has been set, for example, with whatever command line parameters there may have been. // Not that this class would know anything about command line parameters. It just assumes. var selector = objectifySelector(conf.selector) var theService = {} theService.BACKWARD = 'backward' theService.FORWARD = 'forward' function _getExchange(exchangeId) { if (exchangeId === undefined) { exchangeId = selector.exchange_id } var rtn = undefined try { rtn = require(path.resolve(__dirname, `../../extensions/exchanges/${exchangeId}/exchange`))(conf) } catch(err) { // hold comment } return rtn } theService.getExchange = (exchangeId) => { return _getExchange(exchangeId) } theService.getSelector = () => { return selector } theService.isTimeSufficientlyLongAgo = (time, targetTimeInMillis) => { if (time === undefined) return false var exchange = _getExchange() var rtn = false // TODO: phase out in favor of calling exchange.getDirection() if (exchange.historyScan === 'backward') rtn = time < targetTimeInMillis else rtn = time > targetTimeInMillis return rtn } return theService } ================================================ FILE: lib/services/resume-marker-service.js ================================================ var collectionService = require('./collection-service'), objectifySelector = require('../objectify-selector'), crypto = require('crypto') module.exports = function (conf) { // ASSUMES c.selector has been set, for example, with whatever command line parameters there may have been. // Not that this class would know anything about command line parameters. It just assumes. var selector = objectifySelector(conf.selector) var collectionServiceInstance = collectionService(conf) var theService = {} var ranges = [] var direction = 'backward' var pingCount = 0 theService.setDirection = (d) => { direction = d } theService.getRanges = () => { return ranges } function _createNewRange(obj) { var range = {from: obj.trade_id, to: obj.trade_id, oldest_time: obj.time, newest_time: obj.time, selector: selector.normalized} ranges.push(range) if (direction == 'backward') { ranges = ranges.sort((a, b) => { return b.from - a.from }) } else { ranges = ranges.sort((a, b) => { return a.to - b.to }) } range.id = crypto.randomBytes(4).toString('hex') range._id = range.id return range } theService.createNewRange = (obj) => { return _createNewRange(obj) } function _isWithinRange(obj) { var id = obj.trade_id var record = ranges.find((record) => { return record.from <= id && record.to >= id }) return record } theService.isWithinRange = (obj) => { return _isWithinRange(obj) } function _isWithinDistanceOfOneOfAnyRange(obj) { var id = obj.trade_id var record = ranges.find((record) => { return (record.from - 1) <= id && (record.to + 1) >= id }) return record } theService.isWithinOneOfAnyRange = (obj) => { return _isWithinDistanceOfOneOfAnyRange(obj) } function _extendARange(obj) { var record = ranges.find((record) => { return (record.from - 1) <= obj.trade_id && (record.to + 1) >= obj.trade_id }) if (record !== undefined) { if (direction == 'backward') { record.from = obj.trade_id record.oldest_time = obj.time } else { record.to = obj.trade_id record.newest_time = obj.time } } return record } theService.extendARange = (obj) => { return _extendARange(obj) } function _merge() { var rtn = false // true when we have gone through the list, and done one merge. Indicates another merge might be fruitful. if (ranges.length > 1) { var curr = 0 var next = 1 var newRanges = [] do { if (direction == 'backward') { if (ranges[curr].from === (ranges[next].to + 1)) { ranges[curr].from = ranges[next].from ranges[curr].oldest_time = ranges[next].oldest_time newRanges.push(ranges[curr]) curr += 2 next += 2 rtn = true } else { newRanges.push(ranges[curr]) curr += 1 if (next+1 >= ranges.length) newRanges.push(ranges[next]) next += 1 } } else { if (ranges[curr].to === (ranges[next].from - 1)) { ranges[curr].to = ranges[next].to ranges[curr].newest_time = ranges[next].newest_time newRanges.push(ranges[curr]) curr += 2 next += 2 rtn = true } else { newRanges.push(ranges[curr]) curr += 1 if (next+1 >= ranges.length) newRanges.push(ranges[next]) next += 1 } } } while (next < ranges.length) ranges = newRanges } return rtn } theService.merge = () => { return _merge() } theService.ping = (obj) => { var theFarthestIdInRange = -1 var rtn = _isWithinRange(obj) if (rtn !== undefined) { if (direction == 'backward') theFarthestIdInRange = rtn.from else theFarthestIdInRange = rtn.to } else{ rtn = _isWithinDistanceOfOneOfAnyRange(obj) if (rtn !== undefined) { rtn = _extendARange(obj) while (_merge()) rtn = ranges[0] } else { rtn = _createNewRange(obj) } if (direction == 'backward') theFarthestIdInRange = rtn.from else theFarthestIdInRange = rtn.to pingCount++ } return theFarthestIdInRange } theService.load = (cb) => { collectionServiceInstance.getResumeMarkers().find({selector: selector.normalized}).toArray(function (err, data) { ranges = data if (cb !== undefined) cb() }) } theService.flush = (cb) => { if (ranges.length > 0) { collectionServiceInstance.getResumeMarkers().deleteMany({selector: selector.normalized}, function(/*err, data*/) { if (ranges.length > 1) { collectionServiceInstance.getResumeMarkers().insertMany(ranges, function(err/*, data*/) { if (err) throw err if (cb !== undefined) cb() }) } else { collectionServiceInstance.getResumeMarkers().insertOne(ranges[0], function(err/*, data*/) { if (err) throw err if (cb !== undefined) cb() }) } }) } else { if (cb !== undefined) cb() } } theService.getPingCount = () => { return pingCount } return theService } ================================================ FILE: lib/services/trades-service.js ================================================ var collectionService = require('./collection-service'), exchangeService = require('./exchange-service') module.exports = function (conf) { var collectionServiceInstance = collectionService(conf) var exchangeServiceInstance = exchangeService(conf) var theService = {} theService.getTrades = function (tradeId, queryAttributes, exchangeAttributes) { if (queryAttributes === undefined) queryAttributes = _getInitialQueryAttributes(tradeId) if (exchangeAttributes === undefined) exchangeAttributes = _getInitialExchangeAttributes(tradeId) return new Promise(function (resolve/*, reject*/) { // check the database, collectionServiceInstance.getTrades().find(queryAttributes).limit(100).toArray(function (err, data) { if (data.length === 0) { // if not the database, then check the exchange's api if (exchangeServiceInstance.getExchange().historyScanUsesTime) { var id = _getFromOrToFromExchangeAttributes(exchangeAttributes) if (id) { // this exchange uses time to get its trades. So before we call the exchange for // this batch of trades, we'll need to get the trade object belonging to the ID // that was passed in // TODO: We should just be able to pass the exchange the tradeId, and if it needs // to get the trade object, it would do it itself. That keeps this tradesService // more general. var selectorNormalized = exchangeServiceInstance.getSelector().normalized collectionServiceInstance.getTrades() .findOne({id: selectorNormalized+'-'+id}) .then((result) => { _setFromOrToOnExchangeAttributesToTime(result, exchangeAttributes) resolveUsingExchangeServiceGetTrades() }) } else { resolveUsingExchangeServiceGetTrades() } } else { resolveUsingExchangeServiceGetTrades() } } else { resolve(data) } }) function resolveUsingExchangeServiceGetTrades() { exchangeServiceInstance.getExchange().getTrades(exchangeAttributes, function(err, results) { if (err) throw err // add our internal id to the trade results.map((trade) => { trade.trade_id *= 1 // force trade id to a number trade.selector = exchangeServiceInstance.getSelector().normalized trade.id = trade.selector + '-' + trade.trade_id }) resolve(results) }) } }) } function _getInitialQueryAttributes(tradeId) { var q = {} var selectorNormalized = exchangeServiceInstance.getSelector().normalized q.id = new RegExp('/^' + selectorNormalized + '/') if (tradeId !== undefined) q.trade_id = { $lt: tradeId } return q } function _getInitialExchangeAttributes(tradeId) { var q = {} q.product_id = exchangeServiceInstance.getSelector().asset + '-' + exchangeServiceInstance.getSelector().currency if (tradeId !== undefined){ if (exchangeServiceInstance.getExchange().historyScan == exchangeServiceInstance.BACKWARD) { q.to = tradeId } else { q.from = tradeId } } return q } theService.getInitialQueryAttributes = function(tradeId) { return _getInitialQueryAttributes(tradeId) } theService.getInitialExchangeAttributes = function(tradeId) { return _getInitialExchangeAttributes(tradeId) } function _getFromOrToFromExchangeAttributes(ea) { if (exchangeServiceInstance.getExchange().historyScan == exchangeServiceInstance.BACKWARD) { return ea.to } else { return ea.from } } function _setFromOrToOnExchangeAttributesToTime(trade, ea) { if (exchangeServiceInstance.getExchange().historyScan == exchangeServiceInstance.BACKWARD) { ea.to = trade.time } else { ea.from = trade.time } } return theService } ================================================ FILE: lib/slow_stochastic.js ================================================ module.exports = function slow_stochastic (s, key, k, d) { if (!k) k = 14 if (!d) d = 3 if (s.lookback.length >= k + d * 2) { let stochK = [] for (let j = 0; j < d; j++) { let stochs = [] for (let i = 0; i < d; i++) stochs.push((function(x, length) { let low = [], high = [] x.slice(0, length).forEach(function (period) { low.push(period.low) high.push(period.high) }) return 100 * (x[0].close - Math.min(...low)) / (Math.max(...high) - Math.min(...low)) })(s.lookback.slice(i+j), k)) stochK.push(stochs.reduce((sum, cur) => { return sum + cur }, 0) / d) } let stochD = stochK.reduce((sum, cur) => { return sum + cur }, 0) / d s.period[key] = { K: stochK[0], D: stochD } } } ================================================ FILE: lib/sma.js ================================================ module.exports = function sma (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length >= length) { let SMA = s.lookback .slice(0, length) .reduce((sum, cur) => { return sum + cur[source_key] }, 0) s.period[key] = SMA / length } } ================================================ FILE: lib/srsi.js ================================================ var mathjs = require('mathjs') var rsi = require('./rsi') module.exports = function srsi(s, key, rsi_periods, k_periods, d_periods) { let samplesRequiredForStochRSI = rsi_periods + k_periods + 1 if (s.lookback.length >= samplesRequiredForStochRSI - 1) { let RSI = [] if (typeof s.period.rsi !== 'undefined') { RSI.push(s.period.rsi) } else { rsi(s, 'rsi', rsi_periods) RSI.push(s.period.rsi) } s.lookback.slice(0, samplesRequiredForStochRSI - 1).forEach(function (period) { if (period.rsi) { RSI.push(period.rsi) } }) RSI.reverse() if(RSI.length >= samplesRequiredForStochRSI) { let stochRSI = [] for(let i = 0; i < (k_periods + d_periods - 1); i++) { let rsiForPeriod = RSI.slice(i, rsi_periods + i) let highestRSI = Math.max(...rsiForPeriod) let lowestRSI = Math.min(...rsiForPeriod) if(highestRSI == lowestRSI) { stochRSI.push(0) } else { stochRSI.push(((RSI[(rsi_periods - 1) + i] - lowestRSI) / (highestRSI - lowestRSI)) * 100) } } stochRSI.reverse() let percentK = [] for(let i = 0; i < k_periods; i++) { let kData = stochRSI.slice(i, k_periods + i) if(kData.length == k_periods) { percentK.push(mathjs.mean(kData)) } } let percentD = [] for(let i = 0; i < d_periods; i++) { let dData = percentK.slice(i, d_periods + i) if(dData.length == d_periods) { percentD.push(mathjs.mean(dData)) } } s.period[key + '_K'] = percentK[0] == 0 ? 0 : mathjs.round(percentK[0], 2) s.period[key + '_D'] = percentD[0] == 0 ? 0 : mathjs.round(percentD[0], 2) //console.log('lib.srsi: For RSI', RSI[RSI.length - 1], '-', '%K is', s.period[key + '_K'], ', %D is', s.period[key + '_D'], ', period info', s.period); } } } ================================================ FILE: lib/stddev.js ================================================ module.exports = function stddev (s, key, length, source_key) { if (typeof s.period[source_key] === 'number') { var sum = s.period[source_key] var sum_len = 1 for (var idx = 0; idx < length; idx++) { if (typeof s.lookback[idx][source_key] === 'number') { sum += s.lookback[idx][source_key] sum_len++ } else { break } } var avg = sum / sum_len var var_sum = 0 for (idx = 0; idx < sum_len - 1; idx++) { var_sum += Math.pow(s.lookback[idx][source_key] - avg, 2) } var variance = var_sum / sum_len s.period[key] = Math.sqrt(variance) } } ================================================ FILE: lib/ta_bollinger.js ================================================ var talib = require('talib') module.exports = function ta_bollinger(s, key, rsi_periods, DevUp, DevDn, d_ma_type) { return new Promise(function(resolve, reject) { //dont calculate until we have enough data if (s.lookback.length >= rsi_periods) { let tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) //doublecheck length. if (tmpMarket.length >= rsi_periods) { // extract int from string input for ma_type let optInMAType = getMaTypeFromString(d_ma_type) talib.execute({ name: 'BBANDS', startIdx: tmpMarket.length-1 , endIdx: tmpMarket.length -1, inReal: tmpMarket, optInTimePeriod: rsi_periods, //RSI 14 default optInNbDevUp: DevUp, // "Deviation multiplier for upper band" Real Default 2 optInNbDevDn: DevDn, //"Deviation multiplier for lower band" Real Default 2 optInMAType:optInMAType // "Type of Moving Average" default 0 }, function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ outRealUpperBand: result.result.outRealUpperBand, outRealMiddleBand: result.result.outRealMiddleBand, outRealLowerBand: result.result.outRealLowerBand }) }) } else { reject('MarketLenth not populated enough') } } else{ reject('MarketLenth not populated enough') } }) } /** * Extract int from string input eg (SMA = 0) * * @see https://github.com/oransel/node-talib * @see https://github.com/markcheno/go-talib/blob/master/talib.go#L20 */ function getMaTypeFromString(maType) { // no constant in lib? switch (maType.toUpperCase()) { case 'SMA': return 0 case 'EMA': return 1 case 'WMA': return 2 case 'DEMA': return 3 case 'TEMA': return 4 case 'TRIMA': return 5 case 'KAMA': return 6 case 'MAMA': return 7 case 'T3': return 8 default: return 0 } } ================================================ FILE: lib/ta_ema.js ================================================ var talib = require('talib') module.exports = function ta_ema (s, length) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } //dont calculate until we have enough data if (s.marketData.close.length >= length) { //fillup marketData for talib. //this might need improvment for performance. //for (var i = 0; i < length; i++) { // s.marketData.close.push(s.lookback[i].close); //} //fillup marketData for talib. let tmpMarket = s.marketData.close.slice() //add current period tmpMarket.push(s.period.close) //doublecheck length. if (tmpMarket.length >= length) { talib.execute({ name: 'EMA', startIdx: 0, endIdx: tmpMarket.length -1, inReal: tmpMarket, optInTimePeriod: length }, function (err, result) { if (err) { console.log(err) reject(err, result) return } //Result format: (note: outReal can have multiple items in the array) // { // begIndex: 8, // nbElement: 1, // result: { outReal: [ 1820.8621111111108 ] } // } resolve({ 'outReal': result.result.outReal[(result.nbElement - 1)], }) }) } } else { resolve() } } }) } ================================================ FILE: lib/ta_macd.js ================================================ var talib = require('talib') module.exports = function macd (s, slow_period, fast_period, signal_period) { return new Promise(function(resolve, reject) { // check parameters // if (fast_period > slow_period) { // console.log('incorrect parameters MACD. (fast_period < slow_period || signal_period > fast_period)') // return; // } //create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } } let periods_necessary = slow_period + signal_period - 1 //dont calculate until we have enough data if (s.marketData.close.length >= periods_necessary) { // fillup marketData for talib. let tmpMarket = s.marketData.close.slice() // add current period tmpMarket.push(s.period.close) talib.execute({ name: 'MACD', startIdx: 0, endIdx: tmpMarket.length - 1, inReal: tmpMarket, optInFastPeriod: fast_period, optInSlowPeriod: slow_period, optInSignalPeriod: signal_period }, function (err, result) { if (err) { reject(err) console.log(err) return } //Result format: (note: outReal can have multiple items in the array) // { // begIndex: 8, // nbElement: 1, // result: { outReal: [ 1820.8621111111108 ] } // } resolve({ 'macd': result.result.outMACD[(result.nbElement - 1)], 'macd_histogram': result.result.outMACDHist[(result.nbElement - 1)], 'macd_signal': result.result.outMACDSignal[(result.nbElement - 1)], }) }) } else { resolve() } }) } ================================================ FILE: lib/ta_macd_ext.js ================================================ var talib = require('talib') module.exports = function ta_macd_ext (s, slow_period, fast_period, signal_period, fast_ma_type, slow_ma_type, signal_ma_type) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } } var periods_necessary = slow_period + signal_period - 1 // Dont calculate until we have enough data if (s.marketData.close.length >= periods_necessary) { //fillup marketData for talib. var tmpMarket = s.marketData.close.slice() //add current period tmpMarket.push(s.period.close) talib.execute({ name: 'MACDEXT', startIdx: 0, endIdx: tmpMarket.length -1, inReal: tmpMarket, optInFastPeriod: fast_period, optInSlowPeriod: slow_period, optInSignalPeriod: signal_period, optInFastMAType: getMaTypeFromString(fast_ma_type), optInSlowMAType: getMaTypeFromString(slow_ma_type), optInSignalMAType: getMaTypeFromString(signal_ma_type), }, function (err, result) { if (err) { reject(err) return } // Result format: (note: outReal can have multiple items in the array) // { // begIndex: 8, // nbElement: 1, // result: { outReal: [ 1820.8621111111108 ] } // } resolve({ 'macd': result.result.outMACD[(result.nbElement - 1)], 'macd_histogram': result.result.outMACDHist[(result.nbElement - 1)], 'macd_signal': result.result.outMACDSignal[(result.nbElement - 1)], }) }) } else { resolve() } }) } /** * Extract int from string input eg (SMA = 0) * * @see https://github.com/oransel/node-talib * @see https://github.com/markcheno/go-talib/blob/master/talib.go#L20 */ function getMaTypeFromString(maType) { // no constant in lib? switch (maType.toUpperCase()) { case 'SMA': return 0 case 'EMA': return 1 case 'WMA': return 2 case 'DEMA': return 3 case 'TEMA': return 4 case 'TRIMA': return 5 case 'KAMA': return 6 case 'MAMA': return 7 case 'T3': return 8 default: return 0 } } ================================================ FILE: lib/ta_ppo.js ================================================ var talib = require('talib') module.exports = function ppo(s, slow_period, fast_period, signal_period, ma_type) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } } // dont calculate until we have enough data let periods_necessary = slow_period + signal_period - 1 if (s.marketData.close.length < periods_necessary) { resolve() return } let tmpMarket = s.marketData.close.slice() // add current period tmpMarket.push(s.period.close) // extract int from string input for ma_type let optInMAType = getMaTypeFromString(ma_type) talib.execute({ name: 'PPO', startIdx: 0, endIdx: tmpMarket.length -1, inReal: tmpMarket, optInFastPeriod: fast_period, optInSlowPeriod: slow_period, optInSignalPeriod: signal_period, optInMAType: optInMAType }, function (err, result) { if (err) { reject(err, result) return } resolve(result.result.outReal[(result.nbElement - 1)]) }) }) } /** * Extract int from string input eg (SMA = 0) * * @see https://github.com/oransel/node-talib * @see https://github.com/markcheno/go-talib/blob/master/talib.go#L20 */ function getMaTypeFromString(maType) { // no constant in lib? switch (maType.toUpperCase()) { case 'SMA': return 0 case 'EMA': return 1 case 'WMA': return 2 case 'DEMA': return 3 case 'TEMA': return 4 case 'TRIMA': return 5 case 'KAMA': return 6 case 'MAMA': return 7 case 'T3': return 8 default: return 0 } } ================================================ FILE: lib/ta_stoch.js ================================================ var talib = require('talib') module.exports = function stoch(s, key, k_periods, sk_periods, k_ma_type, d_periods, d_ma_type, optMarket) { return new Promise(function(resolve, reject) { let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000) tmpMarket.reverse() //add current period tmpMarket.push(s.period) } let tmpMarketHigh = tmpMarket.map(x => x.high) let tmpMarketClose = tmpMarket.map(x => x.close) let tmpMarketLow = tmpMarket.map(x => x.low) if (tmpMarket.length >= Math.max(k_periods,d_periods,sk_periods) ) { let optInSlowDMAType = getMaTypeFromString(d_ma_type) let optInSlowKMAType = getMaTypeFromString(k_ma_type) talib.execute({ name: 'STOCH', startIdx: 0 , endIdx: tmpMarketClose.length - 1, high: tmpMarketHigh, low: tmpMarketLow, close: tmpMarketClose, optInFastK_Period:k_periods, // K 5 default optInSlowK_Period:sk_periods, //Slow K 3 default optInSlowK_MAType:optInSlowKMAType, //Slow K maType default 0 optInSlowD_Period:d_periods, // D 3 default optInSlowD_MAType:optInSlowDMAType // type of Fast D default 0 }, function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ k: result.result.outSlowK, d: result.result.outSlowD }) }) } else { resolve() } }) } /** * Extract int from string input eg (SMA = 0) * * @see https://github.com/oransel/node-talib * @see https://github.com/markcheno/go-talib/blob/master/talib.go#L20 */ function getMaTypeFromString(maType) { // no constant in lib? switch (maType.toUpperCase()) { case 'SMA': return 0 case 'EMA': return 1 case 'WMA': return 2 case 'DEMA': return 3 case 'TEMA': return 4 case 'TRIMA': return 5 case 'KAMA': return 6 case 'MAMA': return 7 case 'T3': return 8 default: return 0 } } ================================================ FILE: lib/ta_stochrsi.js ================================================ var talib = require('talib') module.exports = function srsi(s, key, rsi_periods, k_periods, d_periods, d_ma_type, optMarket) { return new Promise(function(resolve, reject) { // Returns the parameters needed to execute left comment for latter reference //var o = talib.explain('STOCHRSI') let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) } else { tmpMarket = tmpMarket.map(x=>x.close) } //dont calculate until we have enough data if (tmpMarket.length > rsi_periods) { //doublecheck length. if (tmpMarket.length >= rsi_periods) { // extract int from string input for ma_type let optInMAType = getMaTypeFromString(d_ma_type) talib.execute({ name: 'STOCHRSI', startIdx: 0 , endIdx: tmpMarket.length -1, inReal: tmpMarket, optInTimePeriod: rsi_periods, //RSI 14 default optInFastK_Period:k_periods, // K 5 default optInFastD_Period:d_periods, // D 3 default optInFastD_MAType:optInMAType // type of Fast D default 0 }, function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ outFastK: result.result.outFastK, outFastD: result.result.outFastD }) }) } else { resolve() } } else { resolve() } }) } /** * Extract int from string input eg (SMA = 0) * * @see https://github.com/oransel/node-talib * @see https://github.com/markcheno/go-talib/blob/master/talib.go#L20 */ function getMaTypeFromString(maType) { // no constant in lib? switch (maType.toUpperCase()) { case 'SMA': return 0 case 'EMA': return 1 case 'WMA': return 2 case 'DEMA': return 3 case 'TEMA': return 4 case 'TRIMA': return 5 case 'KAMA': return 6 case 'MAMA': return 7 case 'T3': return 8 default: return 0 } } ================================================ FILE: lib/ta_trix.js ================================================ var talib = require('talib') module.exports = function trix(s, timeperiod) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } } if (s.marketData.close.length < timeperiod) { resolve() return } let tmpMarket = s.marketData.close.slice() // add current period tmpMarket.push(s.period.close) talib.execute({ name: 'TRIX', startIdx: 0, endIdx: tmpMarket.length -1, inReal: tmpMarket, optInTimePeriod: timeperiod }, function (err, result) { if (err) { reject(err, result) return } resolve(result.result.outReal[(result.nbElement - 1)]) }) }) } ================================================ FILE: lib/ta_ultosc.js ================================================ var talib = require('talib') module.exports = function ultosc(s, min_periods, timeperiod1, timeperiod2, timeperiod3) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.high.push(s.lookback[i].high) s.marketData.low.push(s.lookback[i].low) s.marketData.close.push(s.lookback[i].close) } } if (s.marketData.close.length < min_periods) { resolve() return } let tmpHigh = s.marketData.high.slice() tmpHigh.push(s.period.high) let tmpLow = s.marketData.low.slice() tmpLow.push(s.period.low) let tmpClose = s.marketData.close.slice() tmpClose.push(s.period.close) talib.execute({ name: 'ULTOSC', startIdx: 0, endIdx: tmpHigh.length -1, high: tmpHigh, low: tmpLow, close: tmpClose, optInTimePeriod1: timeperiod1, optInTimePeriod2: timeperiod2, optInTimePeriod3: timeperiod3, }, function (err, result) { if (err) { reject(err, result) return } resolve(result.result.outReal[(result.nbElement - 1)]) }) }) } ================================================ FILE: lib/ta_volume.js ================================================ // allows to use all talib Volume Indicator Functions: https://mrjbq7.github.io/ta-lib/func_groups/volume_indicators.html // AD - Chaikin A/D Line // ADOSC - Chaikin A/D Oscillator // OBV - On Balance Volume var talib = require('talib') module.exports = function volume(s, min_periods, indicator, fastperiod, slowperiod) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.high.push(s.lookback[i].high) s.marketData.low.push(s.lookback[i].low) s.marketData.close.push(s.lookback[i].close) s.marketData.volume.push(s.lookback[i].volume) } } if (s.marketData.close.length < min_periods) { resolve() return } let tmpHigh = s.marketData.high.slice() tmpHigh.push(s.period.high) let tmpLow = s.marketData.low.slice() tmpLow.push(s.period.low) let tmpClose = s.marketData.close.slice() tmpClose.push(s.period.close) let tmpVolume = s.marketData.volume.slice() tmpVolume.push(s.period.volume) talib.execute({ name: indicator, startIdx: 0, endIdx: tmpHigh.length -1, high: tmpHigh, low: tmpLow, close: tmpClose, volume: tmpVolume, inReal: tmpClose, optInFastPeriod: fastperiod || 3, optInSlowPeriod: slowperiod || 20 }, function (err, result) { if (err) { reject(err, result) return } resolve(result.result.outReal[(result.nbElement - 1)]) }) }) } ================================================ FILE: lib/ta_willr.js ================================================ // tablib: WILLR - Williams' %R https://mrjbq7.github.io/ta-lib/func_groups/momentum_indicators.html var talib = require('talib') module.exports = function ppo(s, min_periods, timeperiod) { return new Promise(function(resolve, reject) { // create object for talib. only close is used for now but rest might come in handy if (!s.marketData) { s.marketData = { open: [], close: [], high: [], low: [], volume: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.high.push(s.lookback[i].high) s.marketData.low.push(s.lookback[i].low) s.marketData.close.push(s.lookback[i].close) s.marketData.volume.push(s.lookback[i].volume) } } if (s.marketData.close.length < min_periods) { resolve() return } let tmpHigh = s.marketData.high.slice() tmpHigh.push(s.period.high) let tmpLow = s.marketData.low.slice() tmpLow.push(s.period.low) let tmpClose = s.marketData.close.slice() tmpClose.push(s.period.close) let tmpVolume = s.marketData.volume.slice() tmpVolume.push(s.period.volume) talib.execute({ name: 'WILLR', startIdx: 0, endIdx: tmpHigh.length -1, high: tmpHigh, low: tmpLow, close: tmpClose, optInTimePeriod: timeperiod || 14, }, function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve(result.result.outReal[(result.nbElement - 1)]) }) }) } ================================================ FILE: lib/tcf.js ================================================ // Trend Continuation Factor, by M.H. Pee module.exports = function tcf (s, key, length, source_key) { if (!source_key) source_key = 'close' if (s.lookback[0] != undefined) { let xChange = s.period[source_key]-s.lookback[0][source_key] let xPlusChange = (xChange > 0) ? xChange : 0 let xMinusChange = (xChange < 0) ? -1*xChange : 0 s.period['xPlusCF'] = (xPlusChange == 0) ? 0 : ((s.lookback[0]['xPlusCF'] != undefined) ? s.lookback[0]['xPlusCF'] : 1) + xPlusChange s.period['xMinusCF'] = (xMinusChange == 0) ? 0 : ((s.lookback[0]['xMinusCF'] != undefined) ? s.lookback[0]['xMinusCF'] : 1) + xMinusChange s.period['xPlus'] = xPlusChange - s.period['xMinusCF'] s.period['xMinus'] = xMinusChange - s.period['xPlusCF'] } if (s.lookback.length > length) { let xPlusTCF = 0 let xMinusTCF = 0 for (var i=length-1; i>=0; i--) { xPlusTCF += s.lookback[i]['xPlus'] xMinusTCF += s.lookback[i]['xMinus'] } s.period[key] = { plus: xPlusTCF, minus: xMinusTCF } } } ================================================ FILE: lib/ti_bollinger.js ================================================ var tulind = require('tulind') module.exports = function ti_bollinger(s, key, rsi_periods, StdDev, optMarket) { return new Promise(function(resolve, reject) { //dont calculate until we have enough data let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) } else { tmpMarket = tmpMarket.map(x=>x.close) } if ( tmpMarket.length >= rsi_periods) { //doublecheck length. if (tmpMarket.length >= rsi_periods) { // extract int from string input for ma_type tulind.indicators.bbands.indicator( [tmpMarket], [rsi_periods, StdDev] , function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ LowerBand: result[0], MiddleBand: result[1], UpperBand: result[2] }) }) } else { reject('MarketLenth not populated enough') } } else { reject('MarketLenth not populated enough')} }) } ================================================ FILE: lib/ti_hma.js ================================================ // Hull Moving Average: // https://tulipindicators.org/hma var ti = require('tulind') module.exports = function hma(s, min_periods, trend_full) { return new Promise(function(resolve) { if (!s.marketData) { s.marketData = { close: [] } } if (s.lookback.length > s.marketData.close.length) { for (var i = (s.lookback.length - s.marketData.close.length) - 1; i >= 0; i--) { s.marketData.close.push(s.lookback[i].close) } } if (s.marketData.close.length < min_periods) { resolve() return } let tmpClose = s.marketData.close.slice() tmpClose.push(s.period.close) ti.indicators.hma.indicator([tmpClose], [trend_full], function(err, results) { resolve(results[0][results[0].length-1]) }) }) } ================================================ FILE: lib/ti_macd.js ================================================ var tulind = require('tulind') module.exports = function macd(s, key, shortPeriod, longPeriod, signalPeriod ,optMarket) { return new Promise(function(resolve, reject) { if (s.lookback.length >= Math.max(shortPeriod,longPeriod) ) { let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) } else { tmpMarket = tmpMarket.map(x=>x.close) } tulind.indicators.macd.indicator( [tmpMarket], [shortPeriod, longPeriod, signalPeriod] , function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ macd: result[0], macd_signal: result[1], macd_histogram: result[2] }) }) } else { reject() } }) } ================================================ FILE: lib/ti_rsi.js ================================================ var tulind = require('tulind') module.exports = function ti_rsi(s, key, rsi_period, optMarket) { return new Promise(function(resolve, reject) { //dont calculate until we have enough data let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) } else { tmpMarket = tmpMarket.map(x=>x.close) } if ( tmpMarket.length >= rsi_period) { //doublecheck length. if (tmpMarket.length >= rsi_period) { // extract int from string input for ma_type tulind.indicators.rsi.indicator( [tmpMarket], [rsi_period] , function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ rsi: result[0] }) }) } else { reject('MarketLenth not populated enough') } } else { reject('MarketLenth not populated enough')} }) } ================================================ FILE: lib/ti_stoch.js ================================================ var tulind = require('tulind') module.exports = function stoch(s, key, k_periods, sk_periods, d_periods, optMarket) { return new Promise(function(resolve, reject) { if (s.lookback.length >= Math.max(k_periods,d_periods,sk_periods) ) { //dont calculate until we have enough data let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000) tmpMarket.reverse() //add current period tmpMarket.push(s.period) } let tmpMarketHigh = tmpMarket.map(x => x.high) let tmpMarketClose = tmpMarket.map(x => x.close) let tmpMarketLow = tmpMarket.map(x => x.low) // addCurrentPeriod tulind.indicators.stoch.indicator( [tmpMarketHigh,tmpMarketLow, tmpMarketClose ], [k_periods, sk_periods, d_periods] , function (err, result) { if (err) { console.log(err) reject(err, result) return } resolve({ k: result[0], d: result[1] }) }) } else { resolve() } }) } ================================================ FILE: lib/ti_stochrsi.js ================================================ var tulind = require('tulind') module.exports = function ti_stochrsi(s, key, rsi_period, k_periods, d_periods, optMarket) { return new Promise(function(resolve, reject) { //dont calculate until we have enough data let tmpMarket = optMarket if (!tmpMarket) { tmpMarket = s.lookback.slice(0, 1000).map(x=>x.close) tmpMarket.reverse() //add current period tmpMarket.push(s.period.close) } else { tmpMarket = tmpMarket.map(x=>x.close) } if ( tmpMarket.length >= rsi_period) { //doublecheck length. if (tmpMarket.length >= rsi_period) { // extract int from string input for ma_type tulind.indicators.rsi.indicator( [tmpMarket], [rsi_period] , function (err, result) { if (err) { console.log(err) reject(err, result) return } let trsi = result[0] // 0 oldest -- end newest trsi.reverse() let stochRSI = [] for(let i = 0; i < (k_periods + d_periods - 1); i++) { let rsiForPeriod = trsi.slice(i, rsi_period + i) let highestRSI = Math.max(...rsiForPeriod) let lowestRSI = Math.min(...rsiForPeriod) if(highestRSI == lowestRSI) { stochRSI.push(0) } else { stochRSI.push(((trsi[ (rsi_period - 1) + i] - lowestRSI) / (highestRSI - lowestRSI)) ) } } let percentK = [] for(let i = 0; i < k_periods; i++) { let kData = stochRSI.slice(i, k_periods + i) if(kData.length == k_periods) { percentK.push(kData.reduce((a,b) => a + b, 0) / kData.length ) } } let percentD = [] for(let i = 0; i < d_periods; i++) { let dData = stochRSI.slice(i, d_periods + i) if(dData.length == d_periods) { percentD.push(dData.reduce((a,b) => a + b, 0) / dData.length) } } resolve({ stochRSI: stochRSI, stochk :percentK, stochd :percentD }) }) } else { reject('MarketLenth not populated enough') } } else { reject('MarketLenth not populated enough')} }) } ================================================ FILE: lib/vma.js ================================================ // Variable Moving Average, by Tushar S. Chande // VMA automatically adjusts its smoothing constant on the basis of Market Volatility module.exports = function vma (s, key, length, source_key) { if (!source_key) source_key = 'close' let k = 1.0 / length if (s.lookback[0] != undefined) { let pdm = Math.max(s.period[source_key] - s.lookback[0][source_key], 0) let mdm = Math.max(s.lookback[0][source_key] - s.period[source_key], 0) let pdmS = s.period['pdmS'] = k * pdm + ((s.lookback[0]['pdmS'] != undefined) ? s.lookback[0]['pdmS'] * (1 - k) : 0) let mdmS = s.period['mdmS'] = k * mdm + ((s.lookback[0]['mdmS'] != undefined) ? s.lookback[0]['mdmS'] * (1 - k) : 0) let s0 = pdmS + mdmS let pdi = pdmS / s0 let mdi = mdmS / s0 let pdiS = s.period['pdiS'] = k * pdi + ((s.lookback[0]['pdiS'] != undefined) ? s.lookback[0]['pdiS'] * (1 - k) : 0) let mdiS = s.period['mdiS'] = k * mdi + ((s.lookback[0]['mdiS'] != undefined) ? s.lookback[0]['mdiS'] * (1 - k) : 0) let d = Math.abs(pdiS - mdiS) let s1 = pdiS + mdiS var iS = s.period['iS'] = k * d / s1 + ((s.lookback[0]['iS'] != undefined) ? s.lookback[0]['iS'] * (1 - k) : 0) } if (s.lookback.length > length) { let hhv, llv s.lookback.slice(0, length).forEach(function (period) { hhv = (hhv != undefined) ? Math.max(hhv, period['iS']) : period['iS'] llv = (llv != undefined) ? Math.min(llv, period['iS']) : period['iS'] }) hhv = Math.max(hhv, iS) llv = Math.min(llv, iS) let d1 = hhv - llv let vI = (iS - llv) / d1 let vma = s.period['vma'] = k * vI * s.period[source_key] + ((s.lookback[0]['vma'] != undefined) ? s.lookback[0]['vma'] * (1 - k * vI) : 0) s.period[key] = vma } } ================================================ FILE: lib/vwap.js ================================================ module.exports = function vwap (s, key, length, max_period, source_key) { if (!source_key) source_key = 'close' if (s.lookback.length >= length) { if(!s.vwap){ s.vwap = 0, s.vwapMultiplier = 0, s.vwapDivider = 0, s.vwapCount = 0 } if(max_period && s.vwapCount > max_period){ s.vwap = 0, s.vwapMultiplier = 0, s.vwapDivider = 0, s.vwapCount = 0 } s.vwapMultiplier = s.vwapMultiplier + parseFloat(s.period[source_key]) * parseFloat(s.period['volume']) s.vwapDivider = s.vwapDivider + parseFloat(s.period['volume']) s.period[key] = s.vwap = s.vwapMultiplier / s.vwapDivider s.vwapCount++ } } ================================================ FILE: lib/wto.js ================================================ module.exports = function wto (s, key, length, source_key) { if (!source_key) source_key = 'close' let ema = function(x, y, p) { let alpha = (2 / (y + 1) ) let ema = (x - p) * alpha + p return ema } if (!s.period['wto_d']) s.period['wto_d'] = 0 if (!s.period['wto_esa']) s.period['wto_esa'] = 0 if (!s.period[key]) s.period[key] = 0 if (s.lookback.length >= length) { let ap = (s.period['close'] + s.period['high'] + s.period['low']) / 3 s.period['hcl3'] = ap var prev_esa = s.lookback[0]['wto_esa'] if (typeof prev_esa !== 'undefined' && ! isNaN(prev_esa)) { let esa = ema(ap, length, prev_esa) s.period['wto_esa'] = esa var prev_d = s.lookback[0]['wto_d'] if (typeof prev_d !== 'undefined' && ! isNaN(prev_d)) { let d = ema(Math.abs(ap - esa), length, prev_d) s.period['wto_d'] = d let ci = (ap - esa) / (0.015 * d) var prev_tci = s.lookback[0][key] if (typeof prev_tci !== 'undefined' && ! isNaN(prev_tci)) { let tci = ema(ci, s.options.wavetrend_average_length, prev_tci) s.period[key] = tci } } } } } ================================================ FILE: models/README.md ================================================ ## Models Trained models will be placed here! ================================================ FILE: package.json ================================================ { "name": "zenbot4", "version": "4.1.0", "description": "Cryptocurrency trading bot", "bugs": "https://github.com/deviavir/zenbot/issues", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/deviavir/zenbot.git" }, "main": "./index.js", "bin": { "zenbot": "./zenbot.sh" }, "scripts": { "lint": "eslint **/*.js", "lint-fix": "eslint **/*.js --fix", "precommit": "lint-staged", "test": "jasmine test/**/**.test.js", "test-one": "jasmine $PATH_TO_TEST", "postinstall": "node post_install.js", "snyk-protect": "snyk protect", "prepare": "npm run snyk-protect" }, "lint-staged": { "*.js": [ "eslint --fix", "git add" ] }, "dependencies": { "@babel/core": "^7.17.2", "@slack/client": "^5.0.2", "adamant-api": "^1.3.0", "async": "^3.2.3", "babel-loader": "^8.2.3", "babel-preset-env": "^1.6.1", "bitfinex-api-node": "^4.0.16", "bitstamp": "^1.0.4", "bl": "^4.0.3", "bollinger-bands": "^3.0.2", "bootstrap": "^4.6.0", "ccxt": "^1.72.64", "cexio-api-node": "^1.0.8", "cliff": "^0.1.10", "coinbase-pro": "^0.9.0", "colors": "^1.4.0", "commander": "^5.1.0", "convnetjs": "0.3.0", "counterup": "^1.0.2", "css-loader": "^5.2.6", "echarts": "^5.3.0", "ejs": "^3.1.6", "exports-loader": "^0.7.0", "expose-loader": "^1.0.3", "express": "^4.17.2", "express-rate-limit": "^5.5.1", "file-loader": "^6.2.0", "fs": "0.0.2", "gemini-api": "^2.0.4", "glob": "^7.2.0", "har-validator": "^5.1.5", "husky": "^5.2.0", "idgen": "^2.0.2", "imports-loader": "^0.8.0", "ip": "~1.1.5", "jasmine": "^3.99.0", "jquery": "^3.6.0", "jsonexport": "^2.5.2", "keltnerchannel": "^1.4.2", "kraken-api": "^1.0.1", "lint-staged": "^10.5.3", "lodash": "^4.17.21", "lolex": "^6.0.0", "mathjs": "^7.6.0", "micro-request": "^666.0.10", "mime": "^2.6.0", "minimist": "^1.2.5", "mini-css-extract-plugin": "^1.6.2", "mock-require": "^3.0.2", "moment": "^2.29.1", "mongodb": "^3.7.3", "node-bittrex-api": "^0.8.2", "node-prowl": "^0.1.8", "node-sass": "^7.0.1", "node-telegram-bot-api": "^0.56.0", "number-abbreviate": "^2.0.0", "numbro": "github:highvelocityspace/numbro", "path": "^0.12.7", "poloniex.js": "1.0.1", "popper.js": "^1.16.1", "postcss-loader": "^4.3.0", "progress": "^2.0.0", "pushbullet": "2.4.0", "pusher-js": "^5.1.1", "random-port": "^0.1.0", "regression": "^2.0.0", "resolve-url-loader": "^4.0.0", "sass-loader": "^8.0.2", "semver": "^7.3.4", "simple-xmpp": "^1.3.0", "stats-lite": "2.2.0", "style-loader": "^1.3.0", "superagent": "^5.3.1", "talib": "^1.1.4", "timebucket": "^0.4.0", "trend": "0.3.0", "tulind": "^0.8.20", "url-loader": "^4.1.1", "waypoints": "^4.0.1", "webpack": "^5.68.0", "webpack-cli": "^4.9.2", "ws": "^7.5.7", "zero-fill": "^2.2.4", "snyk": "^1.842.0" }, "devDependencies": { "eslint": "^4.19.1", "geneticalgorithm": "^1.0.1", "json2csv": "^5.0.0", "round-precision": "^1.0.0", "run-parallel-limit": "^1.0.4", "shelljs": "^0.8.5", "yargs": "^16.1.1" }, "optionalDependencies": { "fsevents": "^2.1.2" }, "engines": { "node": ">=10.0.0" }, "snyk": true } ================================================ FILE: post_install.js ================================================ var shell = require('shelljs') console.log('bundling WebApp components') shell.exec('webpack --mode production') console.log('installing genetic_backtester components') shell.exec('(cd scripts/genetic_backtester/ && npm i)') ================================================ FILE: scripts/auto_backtester/.snyk ================================================ # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. version: v1.19.0 ignore: {} # patches apply the minimum changes required to fix a vulnerability patch: 'npm:lodash:20180130': - json2csv > cli-table2 > lodash: patched: '2020-08-10T08:38:49.559Z' ================================================ FILE: scripts/auto_backtester/backtester.js ================================================ #!/usr/bin/env node /* Zenbot 4 Auto Backtester v2.0 * glennfu * * Usage: Pass in the same parameters as you would to "zenbot sim", EXCEPT for: * 2 parameters you want to be backtested * * Imagine you've just run: * * ./scripts/genetic_backtester/darwin.js --days=1 --asset_capital=0 --currency_capital=500 --selector="binance.EOS-BTC" --population=20 --use_strategies=trend_ema * * and got the following result: * * ./zenbot.sh sim binance.EOS-BTC --avg_slippage_pct=0.045 --buy_stop_pct=40 --markdown_buy_pct=0.37804270974174603 --markup_sell_pct=4.088646046027306 --max_buy_loss_pct=25 --max_sell_loss_pct=25 --max_slippage_pct=5 --min_periods=7 --neutral_rate=auto --order_poll_time=5000 --order_type=maker --oversold_rsi=78 --oversold_rsi_periods=15 --period=73m --period_length=73m --profit_stop_enable_pct=2 --profit_stop_pct=5 --rsi_periods=15 --sell_stop_pct=0 --strategy=trend_ema --trend_ema=4 --start=201802251900 --asset_capital=0 --currency_capital=500 * * which performs like: * end balance: 500.34778000 (0.06%) * buy hold: 500.98047787 (0.19%) * vs. buy hold: -0.13% * 2 trades over 3 days (avg 0.66 trades/day) * win/loss: 1/0 * error rate: 0.00% * * To use the Auto Backtester, simply remove one or two parameters that are in strategies/trend_ema/strategy.js's phenotype definition. * Let's remove `order_type` and `oversold_rsi` * * ./zenbot.sh sim binance.EOS-BTC --avg_slippage_pct=0.045 --buy_stop_pct=40 --markdown_buy_pct=0.37804270974174603 --markup_sell_pct=4.088646046027306 --max_buy_loss_pct=25 --max_sell_loss_pct=25 --max_slippage_pct=5 --min_periods=7 --neutral_rate=auto --order_poll_time=5000 --oversold_rsi_periods=15 --period=73m --period_length=73m --profit_stop_enable_pct=2 --profit_stop_pct=5 --rsi_periods=15 --sell_stop_pct=0 --strategy=trend_ema --trend_ema=4 --start=201802251900 --asset_capital=0 --currency_capital=500 * * Now pass this to backtester.js and add a step_size, like 10, and re-add days=1 from darwin * * ./scripts/auto_backtester/backtester.js --step_size=10 --days=1 --selector=binance.EOS-BTC --avg_slippage_pct=0.045 --buy_stop_pct=40 --markdown_buy_pct=0.37804270974174603 --markup_sell_pct=4.088646046027306 --max_buy_loss_pct=25 --max_sell_loss_pct=25 --max_slippage_pct=5 --min_periods=7 --neutral_rate=auto --order_poll_time=5000 --oversold_rsi_periods=15 --period=73m --period_length=73m --profit_stop_enable_pct=2 --profit_stop_pct=5 --rsi_periods=15 --sell_stop_pct=0 --strategy=trend_ema --trend_ema=4 --start=201802251900 --asset_capital=0 --currency_capital=500 * * See output: * * Auto Backtest of order_type and oversold_rsi completed at 2018-02-27 15:43:28, took 0m 7s, results saved to: * simulations/auto_backtest_201802271543/results_auto_backtest_201802271543.csv * * * Best Result had order_type=taker and oversold_rsi=73 * (trend_ema) Result Fitness 0.006083518953845421, VS Buy and Hold: 0.3% BuyAndHold Balance: 500.980477 End Balance: 502.504339, Wins/Losses 1/0, ROI 0.000000. * ./zenbot.sh sim binance.EOS-BTC --period_length=73m --min_periods=7 --markdown_buy_pct=0.37804270974174603 --markup_sell_pct=4.088646046027306 --order_type=taker --sell_stop_pct=0 --buy_stop_pct=40 --profit_stop_enable_pct=2 --profit_stop_pct=5 --trend_ema=4 --oversold_rsi_periods=15 --oversold_rsi=73 --backtester_generation=16 --strategy=trend_ema --days=1 --avg_slippage_pct=0.045 --max_buy_loss_pct=25 --max_sell_loss_pct=25 --max_slippage_pct=5 --neutral_rate=auto --order_poll_time=5000 --rsi_periods=15 --start=201802251900 --asset_capital=0 --currency_capital=500 * * So you can see our vsBuyHold has gone from -0.13% to 0.30%, an improvement! */ let Phenotypes = require('../../lib/phenotype') , Backtester = require('../../lib/backtester') , argv = require('yargs').argv , moment = require('moment') , path = require('path') , parallel = require('run-parallel-limit') , colors = require('colors') , z = require('zero-fill') , n = require('numbro') , _ = require('underscore') , json2csv = require('json2csv') let PARALLEL_LIMIT = (process.env.PARALLEL_LIMIT && +process.env.PARALLEL_LIMIT) || require('os').cpus().length simArgs = Object.assign({}, argv) if (simArgs.period) simArgs.period_length = simArgs.period delete simArgs.period delete simArgs['$0'] // This comes in to argv all by itself delete simArgs['_'] // This comes in to argv all by itself let debug = simArgs.debug delete simArgs.debug if (simArgs.maxCores) { if (simArgs.maxCores < 1) PARALLEL_LIMIT = 1 else PARALLEL_LIMIT = simArgs.maxCores delete simArgs.maxCores } let population_data = `auto_backtest_${moment().format('YYYYMMDDHHmm')}` let iterationCount = 0 if (simArgs.help || !simArgs.selector || !simArgs.step_size || simArgs.step_size < 2) { console.log('--strategy= only one strategy') console.log('--step_size= number of sims for each parameter, minimum 2') console.log('--maxCores= maximum processes to execute at a time default is # of cpu cores in system') console.log('--selector= ') console.log('--asset_capital= amount coin to start sim with ') console.log('--currency_capital= amount of capital/base currency to start sim with'), console.log('--days= amount of days to use when backfilling') console.log('--sort_results add if you want results.csv sorted by fitness') process.exit(0) } var timeCount = 0 if (simArgs.days) timeCount++ if (simArgs.start) timeCount++ if (simArgs.end) timeCount++ if (timeCount < 2) { console.log('need at least 2 of: days, start, end') process.exit(1) } function runAutoBacktester () { let strategyName = simArgs.strategy let strategyData = require(path.resolve(__dirname, `../../extensions/strategies/${strategyName}/strategy`)) let strategyPhenotypes = strategyData.phenotypes if (!strategyPhenotypes) { console.log(`No phenotypes definition found for strategy ${strategyName}`) process.exit(1) } var pData = Object.assign({}, strategyPhenotypes) var unsetKeys = [] Object.keys(strategyPhenotypes).forEach(function (key) { if (key in simArgs) { pData[key] = simArgs[key] } else { unsetKeys.push(key) } }) if (unsetKeys.length > 2) { console.log(`You omitted values for keys: ${unsetKeys.join(', ')}. You can have at most 2 unset keys`) process.exit(1) } else if (unsetKeys.length <= 0) { console.log(`You must omit at least one key in ${strategyName}'s phenotype for backtesting`) process.exit(1) } console.log(`\n\n=== Running Auto Backtester on ${unsetKeys.join(' and ').blue} ===\n`) Backtester.resetMonitor() Backtester.ensureBackfill() let step_size = simArgs.step_size delete simArgs.step_size let phenotypes = [] let step_size_1 = step_size , step_size_2 = step_size , key1 = unsetKeys[0] , key2 = unsetKeys[1] , p1 = strategyPhenotypes[key1] , p2 = strategyPhenotypes[key2] // If you're iterating through a set, do the whole set regardless of step_size if (p1 && p1.type === 'listOption') step_size_1 = p1.options.length if (p2 && p2.type === 'listOption') step_size_2 = p2.options.length // If we have 2 keys, build all combinations of both, otherwise just loop through the 1 key values if (unsetKeys.length == 2) { for (let i = 0; i < step_size_1; i++) { for (let j = 0; j < step_size_2; j++) { var phenotype = Object.assign({}, pData) phenotype[key1] = Phenotypes.range(p1, i, step_size_1) phenotype[key2] = Phenotypes.range(p2, j, step_size_2) phenotypes.push(phenotype) } } } else { for (let i = 0; i < step_size_1; i++) { var phenotype = Object.assign({}, pData) phenotype[key1] = Phenotypes.range(p1, i, step_size_1) phenotypes.push(phenotype) } } if (debug) console.log(`Running options:`) // Remove duplicates in case something is screwy in combination with step_size higher than the number of options. // No sense in re-running the same thing multiple times phenotypes = _.uniq(phenotypes, function(p, key, a) { if (debug) console.log(`${key1}: ${p[key1]}, ${key2}: ${p[key2]}`) // print all combinations of options return JSON.stringify(p); }); Backtester.init({ simArgs: simArgs, simTotalCount: phenotypes.length, parallelLimit: PARALLEL_LIMIT, writeFile: writeSimDataFile }) let tasks = phenotypes.map(phenotype => { return cb => { phenotype.backtester_generation = iterationCount phenotype.selector = argv.selector Backtester.trackPhenotype(phenotype) var command = Backtester.buildCommand(strategyName, phenotype, `simulations/${population_data}/sim_${iterationCount}_result.html`) command.iteration = iterationCount writeSimDataFile(iterationCount, JSON.stringify(command)) iterationCount++ Backtester.runCommand(strategyName, phenotype, command, cb) } }) Backtester.startMonitor() parallel(tasks, PARALLEL_LIMIT, (err, results) => { Backtester.stopMonitor(`Auto Backtest of ${unsetKeys.join(' and ').blue}`) results = results.filter(function(r) { return !!r }) if (argv.sort_results) results.sort((a, b) => (Number(a.fitness) < Number(b.fitness)) ? 1 : ((Number(b.fitness) < Number(a.fitness)) ? -1 : 0)) // console.log(`results(${results.length}): ${JSON.stringify(results)}`) results.forEach(function(result) { let it = result.params.match(/backtester_generation\":(\d+),/) let phenotype = phenotypes[parseInt(it[1], 10)] result.commandString = phenotype.command.commandString unsetKeys.forEach(function(key) { result[key] = phenotype[key] }) // console.log(`it: ${JSON.stringify(it)}`) }) let fieldsGeneral = unsetKeys.slice(0) let fieldNamesGeneral = unsetKeys.slice(0) fieldsGeneral = fieldsGeneral.concat(['selector', 'fitness', 'vsBuyHold', 'wlRatio', 'frequency', 'strategy', 'order_type', 'endBalance', 'buyHold', 'wins', 'losses', 'period_length', 'min_periods', 'days', 'commandString']) fieldNamesGeneral = fieldNamesGeneral.concat(['Selector', 'Fitness', 'VS Buy Hold (%)', 'Win/Loss Ratio', '# Trades/Day', 'Strategy', 'Order Type', 'Ending Balance ($)', 'Buy Hold ($)', '# Wins', '# Losses', 'Period', 'Min Periods', '# Days', 'Command']) const json2csv = require('json2csv').parse; let dataCSV = json2csv({ data: results, fields: fieldsGeneral, fieldNames: fieldNamesGeneral }) let csvFileName = `simulations/${population_data}/results_${population_data}.csv` // MS Word whines about opening multiple files of the same name console.log(csvFileName) Backtester.writeFileAndFolder(csvFileName, dataCSV) // If we didn't sort them before, definitely sort them now to get the best one if (!argv.sort_results) results.sort((a, b) => (Number(a.fitness) < Number(b.fitness)) ? 1 : ((Number(b.fitness) < Number(a.fitness)) ? -1 : 0)) let best = results[0] // Display best of the generation let best_string = [] unsetKeys.forEach(function(key) { best_string.push(`${key}=${best[key]}`) }) console.log(`\n\nBest Result had ${best_string.join(' and ').green}`) console.log(`(${best.strategy}) Result Fitness ${best.fitness}, VS Buy and Hold: ${z(5, (n(best.vsBuyHold).format('0.0') + '%'), ' ').yellow} BuyAndHold Balance: ${z(5, (n(best.buyHold).format('0.000000')), ' ').yellow} End Balance: ${z(5, (n(best.endBalance).format('0.000000')), ' ').yellow}, Wins/Losses ${best.wins}/${best.losses}, ROI ${z(5, (n(results.roi).format('0.000000') ), ' ').yellow}.`) console.log(best.commandString + '\n') }) } let writeSimDataFile = (iteration, data) => { let jsonFileName = `simulations/${population_data}/sim_${iteration}.json` Backtester.writeFileAndFolder(jsonFileName, data) } Backtester.deLint() runAutoBacktester() ================================================ FILE: scripts/auto_backtester/backtester_trust_distrust.js ================================================ #!/usr/bin/env node /* Zenbot 4.04 Backtester v0.2 * Ali Anari * 05/30/2017 * * Usage: Pass in the same parameters as you would to "zenbot sim", EXCEPT for: * EMA Parameters: "trend_ema", "neutral_rate" * RSI Parameters: "oversold_rsi", "oversold_rsi_periods" * * Example: ./backtester.js gdax.ETH-USD --days=10 --currency_capital=5 --period_length=1m */ let shell = require('shelljs') let parallel = require('run-parallel-limit') let json2csv = require('json2csv') let roundp = require('round-precision') let fs = require('fs') let VERSION = 'Zenbot 4.04 Backtester v0.2' let PARALLEL_LIMIT = require('os').cpus().length let SELL_THRESHOLD_MIN = 0 let SELL_THRESHOLD_MAX = 10 let SELL_THRESHOLD_MAX_MIN = 0 let SELL_THRESHOLD_MAX_MAX = 10 let BUY_THRESHOLD_MIN = 0 let BUY_THRESHOLD_MAX = 10 let SELL_MIN_MIN = 0 let SELL_MIN_MAX = 10 let PERIOD_MIN = 27 let PERIOD_MAX = 27 let countArr = [] let range = (start, end) => { return Array(end - start + 1).fill().map((_, idx) => start + idx) } let product = args => { if(!args.length) return [[]] var prod = product(args.slice(1)), r = [] args[0].forEach(function(x) { prod.forEach(function(p) { r.push([x].concat(p)) }) }) return r } let objectProduct = obj => { var keys = Object.keys(obj), values = keys.map(function(x) { return obj[x] }) return product(values).map(function(p) { var e = {} keys.forEach(function(k, n) { e[k] = p[n] }) return e }) } let runCommand = (strategy, cb) => { countArr.push(1) let command = `./zenbot.sh sim ${simArgs} --strategy=trust_distrust --period_length=${strategy.period_length}m --sell_threshold=${strategy.sell_threshold} --sell_threshold_max=${strategy.sell_threshold_max} --sell_min=${strategy.sell_min} --buy_threshold=${strategy.buy_threshold} --days=30` console.log(`[ ${countArr.length}/${strategies.length} ] ${command}`) shell.exec(command, {silent:true, async:true}, (code, stdout, stderr) => { if (code) { console.error(command) console.error(stderr) return cb(null, null) } cb(null, processOutput(stdout)) }) } let processOutput = output => { let jsonRegexp = /(\{[\s\S]*?\})\send balance/g let endBalRegexp = /end balance: (\d+\.\d+) \(/g let wlRegexp = /win\/loss: (\d+)\/(\d+)/g let errRegexp = /error rate: (.*)%/g let output2 = output.substr(output.length - 3000) let rawParams = jsonRegexp.exec(output2)[1] let params = JSON.parse(rawParams) let endBalance = endBalRegexp.exec(output2)[1] let wlMatch = wlRegexp.exec(output2) let wins = parseInt(wlMatch[1]) let losses = parseInt(wlMatch[2]) let errorRate = errRegexp.exec(output2)[1] let days = parseInt(params.days) let roi = roundp( ((endBalance - params.currency_capital) / params.currency_capital) * 100, 3 ) return { params: rawParams.replace(/[\r\n]/g, ''), endBalance: parseFloat(endBalance), wins: wins, losses: losses, errorRate: parseFloat(errorRate), sellThreshold: params.sell_threshold, sellThresholdMax: params.sell_threshold_max, sellMin: params.sell_min, buyThreshold: params.buy_threshold, days: days, period_length: params.period_length, roi: roi, wlRatio: losses > 0 ? roundp(wins / losses, 3) : 'Infinity', frequency: roundp((wins + losses) / days, 3) } } let strategies = objectProduct({ sell_threshold: range(SELL_THRESHOLD_MIN, SELL_THRESHOLD_MAX), sell_threshold_max: range(SELL_THRESHOLD_MAX_MIN, SELL_THRESHOLD_MAX_MAX), sell_min: range(SELL_MIN_MIN, SELL_MIN_MAX), buy_threshold: range(BUY_THRESHOLD_MIN, BUY_THRESHOLD_MAX), period_length: range(PERIOD_MIN, PERIOD_MAX) }) let tasks = strategies.map(strategy => { return cb => { runCommand(strategy, cb) } }) let args = process.argv args.shift() args.shift() let simArgs = args.join(' ') console.log(`\n--==${VERSION}==--`) console.log(new Date().toUTCString()) console.log(`\nBacktesting [${strategies.length}] iterations...\n`) parallel(tasks, PARALLEL_LIMIT, (err, results) => { console.log('\nBacktesting complete, saving results...') results = results.filter(function (r) { return !!r }) results.sort((a,b) => (a.roi < b.roi) ? 1 : ((b.roi < a.roi) ? -1 : 0)) let fileName = `backtesting_${Math.round(+new Date()/1000)}.csv` let csv = json2csv({ data: results, fields: ['roi', 'errorRate', 'wlRatio', 'frequency', 'endBalance', 'wins', 'losses', 'period', 'days', 'sellThreshold', 'sellThresholdMax', 'sellMin', 'buyThreshold', 'params'], fieldNames: ['ROI (%)', 'Error Rate (%)', 'Win/Loss Ratio', '# Trades/Day', 'Ending Balance ($)', '# Wins', '# Losses', 'Period', '# Days', 'Sell Threshold', 'Sell Threshold Max', 'Sell Min', 'Buy Threshold', 'Full Parameters'] }) fs.writeFile(fileName, csv, err => { if (err) throw err console.log(`\nResults successfully saved to ${fileName}!\n`) }) }) ================================================ FILE: scripts/auto_backtester/package.json ================================================ { "name": "zenbot4_auto_backtester", "version": "0.2.0", "description": "Parallel simulation runner with CSV results", "dependencies": { "json2csv": "^4.5.4", "round-precision": "^1.0.0", "run-parallel-limit": "^1.1.0", "shelljs": "^0.8.5", "strip-ansi": "^7.0.1", "snyk": "^1.849.0" }, "scripts": { "snyk-protect": "snyk protect", "prepare": "npm run snyk-protect" }, "snyk": true } ================================================ FILE: scripts/cron.sh ================================================ #!/bin/sh verify_environment() { if [[ $(node -v | grep -q "v9" ; echo $?) -gt 0 ]]; then echo "not node 9" exit 0 fi } setup_git() { git config --global user.email "travis@travis-ci.org" git config --global user.name "Travis CI" git remote add upstream https://${GH_TOKEN}@github.com/DeviaVir/zenbot.git git checkout unstable git pull upstream unstable } run_cron() { for f in extensions/exchanges/*/update-products.sh; do echo "processing ${f}" ./${f} done } upload_files() { git add . git commit --message "Exchanges: update-products $TRAVIS_BUILD_NUMBER" git push upstream unstable } verify_environment setup_git run_cron upload_files ================================================ FILE: scripts/genetic_algo/Dockerfile ================================================ FROM node:8 # NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh" # # PLEASE DO NOT EDIT IT DIRECTLY. # # ensure local python is preferred over distribution python ENV PATH /usr/local/bin:$PATH # http://bugs.python.org/issue19846 # > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK. ENV LANG C.UTF-8 # runtime dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ tcl \ tk \ && rm -rf /var/lib/apt/lists/* ENV GPG_KEY 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D ENV PYTHON_VERSION 3.6.0 # if this is called "PIP_VERSION", pip explodes with "ValueError: invalid truth value ''" ENV PYTHON_PIP_VERSION 9.0.1 RUN set -ex \ && buildDeps=' \ tcl-dev \ tk-dev \ ' \ && apt-get update && apt-get install -y $buildDeps --no-install-recommends && rm -rf /var/lib/apt/lists/* \ \ && wget -O python.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \ && wget -O python.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \ && export GNUPGHOME="$(mktemp -d)" \ && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$GPG_KEY" \ && gpg --batch --verify python.tar.xz.asc python.tar.xz \ && rm -r "$GNUPGHOME" python.tar.xz.asc \ && mkdir -p /usr/src/python \ && tar -xJC /usr/src/python --strip-components=1 -f python.tar.xz \ && rm python.tar.xz \ \ && cd /usr/src/python \ && ./configure \ --enable-loadable-sqlite-extensions \ && make -j$(nproc) \ && make install \ && ldconfig \ \ # explicit path to "pip3" to ensure distribution-provided "pip3" cannot interfere && if [ ! -e /usr/local/bin/pip3 ]; then : \ && wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ && python3 /tmp/get-pip.py "pip==$PYTHON_PIP_VERSION" \ && rm /tmp/get-pip.py \ ; fi \ # we use "--force-reinstall" for the case where the version of pip we're trying to install is the same as the version bundled with Python # ("Requirement already up-to-date: pip==8.1.2 in /usr/local/lib/python3.6/site-packages") # https://github.com/docker-library/python/pull/143#issuecomment-241032683 && pip3 install --no-cache-dir --upgrade --force-reinstall "pip==$PYTHON_PIP_VERSION" \ # then we use "pip list" to ensure we don't have more than one pip version installed # https://github.com/docker-library/python/pull/100 && [ "$(pip list |tac|tac| awk -F '[ ()]+' '$1 == "pip" { print $2; exit }')" = "$PYTHON_PIP_VERSION" ] \ \ && find /usr/local -depth \ \( \ \( -type d -a -name test -o -name tests \) \ -o \ \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \ \) -exec rm -rf '{}' + \ && apt-get purge -y --auto-remove $buildDeps \ && rm -rf /usr/src/python ~/.cache # make some useful symlinks that are expected to exist RUN cd /usr/local/bin \ && { [ -e easy_install ] || ln -s easy_install-* easy_install; } \ && ln -s idle3 idle \ && ln -s pydoc3 pydoc \ && ln -s python3 python \ && ln -s python3-config python-config RUN apt-get update RUN apt install -y graphviz libgraphviz-dev pkg-config RUN PKG_CONFIG_ALLOW_SYSTEM_LIBS=OHYESPLEASE pip install pygraphviz ADD requirements.txt / RUN pip3 install -r /requirements.txt ADD ../../ /app ADD fabfile.py /app WORKDIR /app RUN /usr/local/bin/npm install RUN npm update ================================================ FILE: scripts/genetic_algo/README.md ================================================ ## Genetic Algorithm by @arpheno For context: - #298 https://github.com/carlos8f/zenbot/issues/298 - the original PR: https://github.com/carlos8f/zenbot/pull/299 - merged PR https://github.com/carlos8f/zenbot/pull/598 - please note that the code has decayed and you may encounter weird things On your host: ``` $ docker-compose up $ docker-compose exec server bash ``` On docker host (or without docker): ``` $ fab backfill_local: $ cd scripts/genetic_algo $ python -m scoop main.py ``` example: ``` $ fab backfill_local:5 $ cd scripts/genetic_algo $ python -m scoop main.py BTC-CUR 3 ``` Important: before usage, create directory scripts/genetic_algo/logs/hof ================================================ FILE: scripts/genetic_algo/conda_environment.yaml ================================================ name: zenbot_env dependencies: - python=3.6 - numpy - networkx - matplotlib - termcolor - pip: - deap - scoop - names - fabric3 ================================================ FILE: scripts/genetic_algo/conf.py ================================================ import random selectors = { 'BTC-CUR': ['gdax.BTC-USD', 'gdax.BTC-EUR', 'gdax.BTC-GBP'], 'ETH-BTC': ['gdax.ETH-BTC'], 'ETH-EUR': ['gdax.ETH-EUR'], 'ETH-USD': ['gdax.ETH-USD'], 'ETH-CUR': ['gdax.ETH-USD', 'gdax.ETH-EUR'], } partitions = 2 selectivity = 0.3 runid = random.randint(1000, 9999) sigma = 20 indpb = 0.3 mutpb = 0.3 cxpb = 0.3 ================================================ FILE: scripts/genetic_algo/constants.py ================================================ Product = str """ ETH-BTC or BTC-CUR""" Selector = str """ . like gdax.ETH-BTC """ ================================================ FILE: scripts/genetic_algo/docker-compose.yml ================================================ server: build: . volumes: - ./conf.js:/app/conf.js - ./extensions:/app/extensions links: - mongodb command: [ "trade", "--paper" ] restart: always tty: true mongodb: image: mongo:latest volumes_from: - mongodb-data command: mongod --smallfiles mongodb-data: image: mongo:latest volumes: - ./data/db:/data/db command: "true" ================================================ FILE: scripts/genetic_algo/evaluation.py ================================================ import datetime import os import random import shlex import subprocess import sys import re import numpy as np from typing import List from termcolor import colored from conf import partitions from evolution.individual_base import Individual from objective_function import soft_maximum_worst_case from parsing import parse_trades, args_for_strategy def pct(x): return x / 100.0 def minutes(x): return str(int(x)) + 'm' def runzen(cmdline): ansi_escape = re.compile(b'\x1b[^m]*m') with open(os.devnull, 'w') as devnull: try: a = subprocess.check_output(shlex.split(cmdline), stderr=devnull) except Exception as e: # print(e) return -100.0, 0.0 profit = a.split(b'}')[-1].splitlines()[3].split(b': ')[-1] profit = ansi_escape.sub(b'', profit)[:-1] trades = parse_trades(a.split(b'}')[-1].splitlines()[4]) trades = ansi_escape.sub(b'', trades) return float(profit), float(trades) class Andividual(Individual): BASE_COMMAND = 'env node ../../zenbot.js sim {instrument} --strategy {strategy} --avg_slippage_pct 0.33 --filename temp.html' def __init__(self, *args,**kwargs): super(Andividual, self).__init__(*args, **kwargs) self.args = args_for_strategy(self.strategy) # period and periodLength are the same and yield errors # if both are used. self.args = [a for a in self.args if a != 'periodLength'] for _ in self.args: self.append(50 + (random.random() - 0.5) * 100) def __repr__(self): return colored(f"{self.cmdline} {super(Andividual, self).__repr__()}", 'grey') def mate(p1, p2): '''overriding function of individual ''' print('overriding mating fct') # do crossover # c1args = np.random.randindt(2, size=len(self.args)) return p1, p2 @property def instrument(self): return random.choice(self.instruments) @property def strategy(self): return random.choice(self.strategies) @property def objective(self): return soft_maximum_worst_case(self) def compress(self): res = dict(zip(self.args, self)) period = res['period'] del res['period'] normalized = {param: self.normalize(value, period) if 'period' in param or param == 'trend_ema' else value for param, value in res.items()} normalized['period'] = period output = dict(self.convert(param, value) for param, value in normalized.items()) return output.items() @property def params(self) -> List[str]: def format(key, value): if isinstance(value, float): return f'--{key} {value:.6f}' else: return f'--{key} {value}' params = [format(key, value) for key, value in self.compress()] return params @property def cmdline(self) -> str: base = self.BASE_COMMAND.format(instrument=self.instrument, strategy=self.strategy) result = ' '.join([base] + self.params) return result def normalize(self, value: float, period: int): return (value / period) def convert(self, param, value): if param == 'period': res = minutes(int(value/2)) elif param == 'min_periods': res = int(value*20) elif param == 'trend_ema': res = int(value*15) elif 'period' in param: res = int(value*10) elif 'pct' in param: res = pct(value) elif 'rate' in param: res = pct(value) elif 'rsi' in param: res = float(value) elif 'sell' in param: res = value/10.0 elif 'buy' in param: res = value/10.0 elif 'threshold' in param: res = value/100000.0 elif 'sar_af' == param: res = value/1000.0 elif 'sar_max_af' == param: res = pct(value) elif 'greed' == param: res = value/10.0 elif 'lastpoints' == param: res = int(value) elif 'avgpoints' == param: res = 10 * int(value) elif 'lastpoints2' == param: res = int(value/10) elif 'avgpoints2' == param: res = int(value/10) elif 'markup_sell_pkt' == param: res = value elif 'markup_buy_pkt' == param: res = value elif 'sell_threshold' in param: res = value/100000.0 elif 'sell_threshold_max' in param: res = value/100000.0 elif 'sell_min' in param: res = value/100000.0 elif 'buy_threshold' in param: res = value/100000.0 elif 'buy_threshold_max' in param: res = value/100000.0 elif 'trigger_factor' == param: res = value/1000.0 elif 'ema_acc' == param: res = value/1000000.0 elif 'srsi' in param: res = value/100000.0 elif 'oversold_cci' == param: res = -value/1000.0 elif 'overbought_cci' == param: res = value/1000.0 elif 'constant' == param: res = value/1000000.0 elif 'ema' in param: res = value/100000.0 elif 'sma' in param: res = value/100000.0 elif 'vwap_length' == param: res = value/100000.0 elif 'vwap_max' == param: res = value/1000.0 elif 'activation_1_type' == param: res = np.random.choice(['sigmoid', 'tanh', 'relu']) elif 'neurons_1' == param: res = value/100000.0 elif 'depth' == param: res = value/100000.0 elif 'selector' == param: res = self.instrument elif 'min_predict' == param: res = value/1000000.0 elif 'momentum' == param: res = value/1000000.0 elif 'threads' == param: res = value/1000000.0 elif 'learns' == param: res = value/1000000.0 elif 'decay' == param: res = value/1000000.0 else: raise ValueError(colored(f"I don't understand {param} please add it to evaluation.py", 'red')) return param, res def evaluate_zen(cmdline:str, days: int): periods = time_params(days, partitions) try: fitness = [] for period in periods: cmd = ' '.join([cmdline, period]) f,t = runzen(cmd) fitness.append(f) if t==0: raise subprocess.CalledProcessError(-1,'TooFewTrades') sys.stdout.write('.') except subprocess.CalledProcessError: fitness = [-100 for _ in periods] sys.stdout.write('x') sys.stdout.flush() return tuple(fitness) def time_params(days: int, partitions: int) -> List[str]: now = datetime.date.today() delta = datetime.timedelta(days=days) splits = [now - delta / partitions * i for i in range(partitions + 1)][::-1] return [f' --start {start} --end {end}' for start, end in zip(splits, splits[1:])] ================================================ FILE: scripts/genetic_algo/evolution/__init__.py ================================================ from functools import partial from deap.tools import History from scoop import futures from evolution.core import algorithm, breed, mutate from halloffame import ObjectiveFunctionHallOfFame from .selection import harsh_winter from .utils import statsa def evolve(evaluate, cls, popsize=10): select = partial(harsh_winter, count=popsize) history = History() stats = statsa() hof = ObjectiveFunctionHallOfFame(maxsize=15) return algorithm(cls, popsize, futures.map, evaluate, select, breed, mutate, stats, history, hof) ================================================ FILE: scripts/genetic_algo/evolution/core.py ================================================ import random from deap.tools import History, Statistics from termcolor import colored from conf import cxpb, mutpb from .utils import log_stuff def algorithm(individual,popsize,map,evaluate,select,breed,mutate,stats,history,hof): # Create initial Population and evaluate it population = set() print(colored(f"Sampling an initial valid population, this may take a while...", 'blue')) while len(population) < popsize: print(colored(f"Currently {len(population)} valid individuals", 'blue')) would_be = [individual() for _ in range(popsize)] evaluate_group(would_be,map,evaluate) population = population | set(would_be) # Commence evolution for g in range(0, 1000): log_stuff(g, history, hof, population, stats) print(colored(f"It's breeding season, we're expecting new members of the tribe...", 'blue')) offspring = breed(population) print(colored(f"Radiation and toxic waste are causing mutations in the population...", 'blue')) mutants = mutate(population) print(colored(f"Summer is here, evaluating our new arrivals...", 'blue')) evaluate_group(offspring + mutants, map,evaluate) survivors = select(set(offspring) | set(mutants) | population) population = survivors return hof def evaluate_group(population, map, evaluate): invalid_ind = [ind for ind in population if not ind.fitness.valid] print(' ' * len(invalid_ind) + '|') fitnesses = map(evaluate, [ind.cmdline for ind in invalid_ind]) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit def breed(population): offspring = [] while len(offspring) < len(population) * cxpb: parent1, parent2 = random.sample(population, 2) child1, child2 = parent1 + parent2 offspring.append(child1) offspring.append(child2) print(colored(len(offspring), 'green') + colored(f" children have been born.", 'blue')) return offspring def mutate(population): mutants = [] for individual in population: if random.random() < mutpb: mutants.append(~individual) print(colored(len(mutants), 'green') + colored(f" individuals have mutated.", 'blue')) return mutants ================================================ FILE: scripts/genetic_algo/evolution/individual_base.py ================================================ from copy import deepcopy, copy import names from deap.base import Fitness from conf import partitions class FitnessMax(Fitness): weights = tuple([1 for _ in range(partitions)]) class Individual(list): mate = lambda *x: x mutate = lambda x: x @property def objective(self): return sum(self) def __repr__(self): return f"{list(self.fitness.values)} {self.objective} {self.name}" def __init__(self, *args, **kwargs): self.name = names.get_full_name() self.fitness = FitnessMax() super(Individual, self).__init__(*args, **kwargs) def __deepcopy__(self, memodict={}): obj = copy(self) obj.fitness = deepcopy(self.fitness) obj.name = names.get_full_name() return obj def __add__(self, other): child1, child2 = self.__class__.mate(deepcopy(self), deepcopy(other)) if False: print(f"\nMating: with {self.__class__.mate}") print(self) print(other) print('Children:') print(child1) print(child2) del child1.fitness.values del child2.fitness.values return child1, child2 def __invert__(self): mutant = self.__class__.mutate(deepcopy(self))[0] # DON'T THINK ABOUT REMOVING THE ZERO if False: print(f"\nMutating: with {self.__class__.mutate}") print(self) print(mutant) del mutant.fitness.values return mutant # def __eq__(self, other): # '''when overriding __eq__ this way, all initial individuals are # considered the same and thus cannot be different set elements! # therefore commenting this out. look for usage of hash equality # ''' # return hash(self)==hash(other) def __hash__(self): return hash(tuple(self.fitness.values)) ================================================ FILE: scripts/genetic_algo/evolution/selection.py ================================================ import random from operator import attrgetter from typing import Iterable, Set from termcolor import colored from conf import partitions from evolution.individual_base import Individual def harsh_winter(population: Set[Individual], count: int) -> Set[Individual]: """ Selects `popsize` many individuals from the current population.""" elitist_count = int(count * 0.3) specialist_count = int(count * 0.4 / partitions) elites = select_elites(population, elitist_count) difference = population - elites specialists = select_specialists(difference, specialist_count) survivors = elites | specialists difference = population - survivors if difference: rest = set(random.sample(difference, count - len(survivors))) population = survivors | rest else: rest = set() population = survivors log_stuff(elites, rest, specialists) return population def select_elites(individuals: Iterable[Individual], count: int): elites = set(sorted(individuals, key=attrgetter('objective'), reverse=True)[:count]) return elites def select_specialists(individuals: Iterable[Individual], count: int): guilds = [sorted(individuals, reverse=True, key=lambda x: x.fitness.values[i]) for i in range(partitions)] specialists = set([ind for specialists in guilds for ind in specialists[:count]]) return specialists def log_stuff(elites, rest: Set, specialists): print(colored("\n\nWinter has come, weeding out the unworthy.", 'blue')) print(f"{len(elites)} Elites will survive, they're currently the strongest:") for elite in sorted(elites, key=attrgetter('objective'), reverse=True): print(elite) print(f"{len(specialists)} Specialists will survive, they're the best in their domain:") for specialist in specialists: print(specialist) print(f"Some other have fought their way through:") for r in random.sample(rest, len(rest) // 5): print(r) print(colored('...', 'grey')) ================================================ FILE: scripts/genetic_algo/evolution/utils.py ================================================ import networkx as networkx import numpy from deap.tools import Statistics from matplotlib import pyplot as plt from termcolor import colored from conf import runid from objective_function import soft_maximum_worst_case def draw(history, toolbox): ax = plt.figure() ax.set_figheight(30) ax.set_figwidth(30) graph = networkx.DiGraph(history.genealogy_tree) graph = graph.reverse() # Make the grah top-down colors_inds = (history.genealogy_history[i] for i in graph) colors = [soft_maximum_worst_case(ind) if ind.fitness.valid else -10 for ind in colors_inds] positions = networkx.drawing.nx_agraph.graphviz_layout(graph, prog="dot") networkx.draw(graph, positions, node_color=colors, ax=ax.add_subplot(111), figsize=(30, 30), node_size=150) ax.savefig('logs/history/{runid}.png'.format(runid=runid)) def log_stuff(g, history, hof, population, stats): # draw(history, toolbox) record = stats.compile(population) hof.update(population) hof.persist() print(colored(f'\nGeneration {g} {record}', 'green') ) # print(hof) def statsa(): stats = Statistics(key=lambda ind: soft_maximum_worst_case(ind)) stats.register("avg", numpy.mean) stats.register("std", numpy.std) stats.register("min", numpy.min) stats.register("max", numpy.max) stats.register("len", len) return stats ================================================ FILE: scripts/genetic_algo/fabfile.py ================================================ import datetime import shlex import subprocess from fabric.api import run, cd, local def sim(instrument, days, popsize, strategy): with cd('zenbot'): params = dict(instrument=instrument, days=days, strategy=strategy, popsize=popsize, timestamp=datetime.datetime.now().strftime('%Y-%m-%d-%H-%M')) cmd = "cd scripts/genetic_algo && python -m scoop main.py {instrument} {days} {popsize} {strategy}".format(**params) total = '(nohup docker-compose exec -T server bash -c "{cmd}" > {instrument}_{strategy}_{days}_{popsize}_{timestamp}.out 2>&1 &) && sleep 1'.format( cmd=cmd, **params) print(total) run(total) def remote(cmd, logfile): with cd('zenbot'): total = '(nohup docker-compose exec -T server bash -c "{cmd}" > {logfile} 2>&1 &) && sleep 1'.format( cmd=cmd, logfile=logfile) print(total) run(total) def backfill_remote(TOTAL_DAYS): products = ['gdax.BTC-EUR', 'gdax.BTC-USD', 'gdax.BTC-GBP']+['gdax.ETH-BTC', 'poloniex.ETH-BTC'] for instrument in products: cmd = 'env node ../../zenbot.js backfill {instrument} --days {days}'.format(days=TOTAL_DAYS, instrument=instrument) remote(cmd, 'backfill_'+instrument) def backfill_local(TOTAL_DAYS): products = ['gdax.BTC-EUR', 'gdax.BTC-USD', 'gdax.BTC-GBP']+['gdax.ETH-BTC', 'poloniex.ETH-BTC'] for instrument in products: cmd = 'env node ../../zenbot.js backfill {instrument} --days {days}'.format(days=TOTAL_DAYS, instrument=instrument) local(cmd) ================================================ FILE: scripts/genetic_algo/halloffame.py ================================================ from operator import attrgetter from conf import runid class ObjectiveFunctionHallOfFame(object): def __init__(self, maxsize=30): self.inner = set() self.maxsize = maxsize def update(self, newpop): self.inner = self.inner.union(newpop) self.inner = set(sorted(self.inner, key=attrgetter('objective'), reverse=True)[:self.maxsize]) def __iter__(self): return iter(self.inner) def len(self): return len(self.inner) def __repr__(self): header = ["Current Hall of Fame:"] report = [f"{ind}" for ind in sorted(self.inner, key=attrgetter('objective'), reverse=True)] return "\n".join(header + report) def persist(self): with open('logs/hof/{runid}.txt'.format(runid=runid), 'w') as f: f.write(str(self)) ================================================ FILE: scripts/genetic_algo/main.py ================================================ import sys from functools import partial from deap.tools import cxTwoPoint, mutGaussian from scoop import shared from termcolor import colored from conf import indpb, sigma, partitions, selectors from evaluation import evaluate_zen, Andividual from evolution import evolve import parsing blue = partial(lambda text, color: colored(str(text), color), color='blue') green = partial(lambda text, color: colored(str(text), color), color='green') def main(instrument, days, popsize, strategy='trend_ema'): print(colored("Starting evolution....", 'blue')) evaluate = partial(evaluate_zen, days=days) print(blue("Evaluating ")+green(popsize)+blue(" individuals over ") + green(days) + blue(' days in ') + green(partitions) + blue(' partitions.')) try: Andividual.instruments = selectors[instrument] except: # if not in the list, assume it is one usable instrument Andividual.instruments = [instrument] Andividual.mate = cxTwoPoint Andividual.mutate = partial(mutGaussian, mu=0, sigma=sigma, indpb=indpb) # Andividual.strategy = strategy strategies = parsing.strategies() Andividual.strategies = [st for st in strategies] print('using strategies:', Andividual.strategies) print(colored(f"Mating function is ", 'blue') + colored(Andividual.mate, 'green')) print(colored(f"Mutating function is ", 'blue') + colored(Andividual.mutate, 'green')) res = evolve(evaluate, Andividual, popsize) return res if __name__ == '__main__': INSTRUMENT = sys.argv[1] TOTAL_DAYS = int(sys.argv[2]) try: popsize = int(sys.argv[3]) except: popsize = 10 try: strategy = sys.argv[4] except: strategy = 'trend_ema' print(colored("MAKE SURE YOU RUN fab backfill_local:", 'red')) print(colored("otherwise it's all crap", 'red')) res = main(INSTRUMENT, TOTAL_DAYS, popsize, strategy) print(res) ================================================ FILE: scripts/genetic_algo/objective_function.py ================================================ import math sum = sum def soft_maximum_worst_case(ind): return -math.log(sum(math.exp(-f) for f in ind.fitness.values)+0.0000000000001) ================================================ FILE: scripts/genetic_algo/parsing.py ================================================ import shlex import subprocess import re def parse_trades(stuff): """ >>> parse_trades("1 trades over 17 days (avg 0.06 trades/day)") '0.06' :param stuff: :return: """ return stuff.split(b'avg')[-1].strip().split()[0] def args_for_strategy(strat): ansi_escape = re.compile(b'\x1b[^m]*m') available = subprocess.check_output(shlex.split('env node ../../zenbot.js list-strategies')) strats = [ansi_escape.sub(b'', strat.strip()) for strat in available.split(b'\n\n')] groups = [group.splitlines() for group in strats] output = {split[0].split()[0]: split[1:] for split in groups if split} result = {strategy: [line.strip().strip(b'-').split(b'=')[0] for line in lines if b'--' in line] for strategy, lines in output.items()} result = {key.decode(): [p.decode() for p in val] for key, val in result.items()} return result[strat] def strategies(): ansi_escape = re.compile(b'\x1b[^m]*m') available = subprocess.check_output(shlex.split('env node ../../zenbot.js list-strategies')) strats = [ansi_escape.sub(b'', strat.strip()) for strat in available.split(b'\n\n')] groups = [group.splitlines() for group in strats] output = {split[0].split()[0]: split[1:] for split in groups if split} result = {strategy: [line.strip().strip(b'-').split(b'=')[0] for line in lines if b'--' in line] for strategy, lines in output.items()} result = [key.decode() for key, val in result.items()] return result ================================================ FILE: scripts/genetic_algo/requirements.txt ================================================ deap numpy networkx matplotlib scoop names fabric3 termcolor ================================================ FILE: scripts/genetic_algo/tests/__init__.py ================================================ ================================================ FILE: scripts/genetic_algo/tests/test_evaluation.py ================================================ from evaluation import fuzz_product from parsing import args_for_strategy from unittest.mock import patch def test_parse_strategies(): asd = b''' macd description: Buy when (MACD - Signal > 0) and sell when (MACD - Signal < 0). options: --period= period length (default: 1h) --min_periods= min. number of history periods (default: 52) --ema_short_period= number of periods for the shorter EMA (default: 12) --ema_long_period= number of periods for the longer EMA (default: 26) --signal_period= number of periods for the signal EMA (default: 9) --up_trend_threshold= threshold to trigger a buy signal (default: 0) --down_trend_threshold= threshold to trigger a sold signal (default: 0) --overbought_rsi_periods= number of periods for overbought RSI (default: 25) --overbought_rsi= sold when RSI exceeds this value (default: 70) sar description: Parabolic SAR options: --period= period length (default: 2m) --min_periods= min. number of history periods (default: 52) --sar_af= acceleration factor for parabolic SAR (default: 0.015) --sar_max_af= max acceleration factor for parabolic SAR (default: 0.3) trend_ema (default) description: Buy when (EMA - last(EMA) > 0) and sell when (EMA - last(EMA) < 0). Optional buy on low RSI. options: --period= period length (default: 10m) --min_periods= min. number of history periods (default: 52) --trend_ema= number of periods for trend EMA (default: 20) --neutral_rate= avoid trades if abs(trend_ema) under this float (0 to disable, "auto" for a variable filter) (default: 0.06) --oversold_rsi_periods= number of periods for oversold RSI (default: 20) --oversold_rsi= buy when RSI reaches this value (default: 30) ''' with patch('evaluation.subprocess.check_output', lambda *x, **y: asd): assert args_for_strategy('sar') == ['period', 'min_periods', 'sar_af', 'sar_max_af'] ================================================ FILE: scripts/genetic_algo/tests/test_evolution.py ================================================ import random from evolution import evolve from evolution.individual import Individual def test_evolve(): class TestIndividual(Individual): def __init__(self,*args,**kwargs): super(TestIndividual, self).__init__(*args,**kwargs) for x in range(5): self.append(random.random()) evolve(lambda x: ((sum(x), sum(x), sum(x))), TestIndividual) ================================================ FILE: scripts/genetic_algo/tests/test_integration.py ================================================ import random from subprocess import CalledProcessError from unittest.mock import patch from main import main def myoutput(cmdline): print(cmdline) if random.random()<0.9: return str(random.random()),str(random.random()) else: raise CalledProcessError('a','b') def test_integration(): with patch('evaluation.runzen',myoutput) as cmd: with patch('evaluation.subprocess.check_output',myoutput): main('gdax.BTC-ETH',120) ================================================ FILE: scripts/genetic_algo/tests/test_objective.py ================================================ from unittest.mock import MagicMock from objective_function import soft_maximum_worst_case def test_obj(): k = lambda x: MagicMock(fitness=MagicMock(values=x)) assert soft_maximum_worst_case(MagicMock(fitness=MagicMock(values=[1, -1.1]))) < soft_maximum_worst_case(MagicMock(fitness=MagicMock(values=[0.1, -0.1]))) assert soft_maximum_worst_case(k([17, -5])) < soft_maximum_worst_case(MagicMock(fitness=MagicMock(values=[7, 5]))) print(soft_maximum_worst_case(k([10, 10, 10, 2, 10])), soft_maximum_worst_case(k([1, 1, 1, 1, 1]))) assert soft_maximum_worst_case(k([10, 10, 10, -10, 10])) < soft_maximum_worst_case(k([1, 1, 1, 1, 1])) assert soft_maximum_worst_case(k([-100, -100])) < soft_maximum_worst_case(k([1, 1, 1, 1, 1])) ================================================ FILE: scripts/genetic_algo/utils.py ================================================ ================================================ FILE: scripts/genetic_algo/zendividual.py ================================================ ================================================ FILE: scripts/genetic_backtester/darwin.js ================================================ #!/usr/bin/env node /* Zenbot 4 Genetic Backtester * Clifford Roche * 07/01/2017 * * Example: ./darwin.js --selector="bitfinex.ETH-USD" --days="10" --currency_capital="5000" --use_strategies="all | macd,trend_ema,etc" --population="101" --population_data="simulations/generation_data_NUMBERS" * Params: * --use_strategies= One or more strategies comma separated. Requires at least one named strategy. * --population_data= The filename used for continuing backtesting from a previous run. * --generateLaunch=| Generate .sh and .bat files using the best generation discovered. * --ignoreLaunchFitness=| If used with --generateLaunch it will always write a new launch file regardless of if the latest fitness is greater. * --floatScanWindow Time window used for analyzing data be adjusted for every generation. * --population= Population per strategy. * --maxCores= Maximum processes to execute at a time. Default is the # of cpu cores in the system. * --selector= The exchange and market pair to target. For example, --selector=gdax.BTC-USDC for Coinbase Pro market with Bitcoin-USDCoin pair. * --asset_capital= Amount of coin available to the simulator to start with. * --currency_capital= Amount of capital/base currency available to the sim to start with. * --days= Amount of days to use when backfilling. * --noStatSave=| Set to true and statistics will not be saved to the simulation folder. * --silent=| Setting to true may improve performance. * --runGenerations= Set the number of generations to be used. Count shown is zero based so, count + 1 = # of generations. * --minTrades= Minimum number of wins before generation is considured fit to evolve. * --fitnessCalcType= Default: Classic. wl will score the highes for wins and losses, profit doesn't care about wins and losses only the higest end balance, classic uses original claculation / profitwl tries to get the highest profit using the lowest win/loss ratio * * * Any parameters for sim and/or strategy can be passed in and will override the genetic test generated parameters. * i.e. if --period_length=1m is passed all tests will be performed using --period_length=1m instead of trying to find that parameter. * */ let parallel = require('run-parallel-limit') let Json2csvParser = require('json2csv').Parser let fs = require('fs') let GeneticAlgorithmCtor = require('geneticalgorithm') let moment = require('moment') let path = require('path') // eslint-disable-next-line no-unused-vars let colors = require('colors') let Phenotypes = require('../../lib/phenotype') let Backtester = require('../../lib/backtester') let argv = require('yargs').argv let z = require('zero-fill') let n = require('numbro') let VERSION = 'Zenbot 4 Genetic Backtester v0.2.3' let PARALLEL_LIMIT = (process.env.PARALLEL_LIMIT && +process.env.PARALLEL_LIMIT) || require('os').cpus().length let iterationCount = 0 let selectedStrategies let pools = {} let simArgs let populationSize = 0 let generationCount = 1 let runGenerations = undefined let generationProcessing = false let population_data = '' let noStatSave = false //let floatScanWindow = false let ignoreLaunchFitness = false let minimumTrades = 0 let fitnessCalcType = 'classic' let readSimDataFile = (iteration) => { let jsonFileName = `simulations/${population_data}/gen_${generationCount}/sim_${iteration}.json` if (fs.existsSync(jsonFileName)) { let simData = JSON.parse(fs.readFileSync(jsonFileName, { encoding: 'utf8' })) return simData } else { return null } } let writeSimDataFile = (iteration, data) => { let jsonFileName = `simulations/${population_data}/gen_${generationCount}/sim_${iteration}.json` Backtester.writeFileAndFolder(jsonFileName, data) } function allStrategyNames() { let pathName = path.resolve(__dirname, '..', '..', 'extensions', 'strategies') return fs.readdirSync(pathName).filter(function (file) { return fs.statSync(pathName + '/' + file).isDirectory() }) } function isUsefulKey(key) { if (key == 'filename' || key == 'show_options' || key == 'sim') return false return true } function generateCommandParams(input) { if (!isUndefined(input) && !isUndefined(input.params)) { input = input.params.replace('module.exports =', '') } input = JSON.parse(input) var result = '' var keys = Object.keys(input) for (let i = 0; i < keys.length; i++) { var key = keys[i] if (isUsefulKey(key)) { // selector should be at start before keys if (key == 'selector') { result = input[key] + result } else result += ' --' + key + '=' + input[key] } } return result } function saveGenerationData(csvFileName, jsonFileName, dataCSV, dataJSON) { try { fs.writeFileSync(csvFileName, dataCSV) console.log('> Finished writing generation csv to ' + csvFileName) } catch (err) { throw err } try { fs.writeFileSync(jsonFileName, dataJSON) console.log('> Finished writing generation json to ' + jsonFileName) } catch (err) { throw err } } // Find the first incomplete generation of this session, where incomplete means no "results" files while (fs.existsSync(`simulations/${population_data}/gen_${generationCount}`)) { generationCount++ } generationCount-- if (generationCount > 0 && !fs.existsSync(`simulations/${population_data}/gen_${generationCount}/results.csv`)) { generationCount-- } function saveLaunchFiles(saveLauchFile, configuration) { if (!saveLauchFile) return //let lConfiguration = configuration.replace(' sim ', ' trade ') let lFilenameNix = new String().concat('./gen.', configuration.selector.toLowerCase(), '.sh') let lFinenamewin32 = new String().concat('./gen.', configuration.selector.toLowerCase(), '.bat') delete configuration.generateLaunch delete configuration.backtester_generation let bestOverallCommand = generateCommandParams(configuration) let lastFitnessLevel = -9999.0 // get prior fitness level nix if (fs.existsSync(lFilenameNix)) { let lFileCont = fs.readFileSync(lFilenameNix, { encoding: 'utf8', flag: 'r' }) let lines = lFileCont.split('\n') if (lines.length > 2) if (lines[1].includes('fitness=')) { let th = lines[1].split('=') lastFitnessLevel = th[1] } } // get prior firness level win32 if (fs.existsSync(lFinenamewin32)) { let lFileCont = fs.readFileSync(lFinenamewin32, { encoding: 'utf8', flag: 'r' }) let lines = lFileCont.split('\n') if (lines.length > 1) if (lines[1].includes('fitness=')) { let th = lines[1].split('=') lastFitnessLevel = th[1] } } //write Nix Version let lNixContents = '#!/bin/bash\n'.concat('#fitness=', configuration.fitness, '\n', 'env node zenbot.js trade ', bestOverallCommand, ' $@\n') let lWin32Contents = '@echo off\n'.concat('rem fitness=', configuration.fitness, '\n', 'node zenbot.js trade ', bestOverallCommand, ' %*\n') if (((Number(configuration.fitness) > Number(lastFitnessLevel)) || (ignoreLaunchFitness)) && Number(configuration.fitness) > 0.0) { fs.writeFileSync(lFilenameNix, lNixContents) fs.writeFileSync(lFinenamewin32, lWin32Contents) // using the string instead of octet as eslint compaines about an invalid number if the number starts with 0 fs.chmodSync(lFilenameNix, '777') fs.chmodSync(lFinenamewin32, '777') } } let cycleCount = -1 function isUndefined(variable) { return typeof variable === typeof undefined } function simulateGeneration(generateLaunchFile) { generationProcessing = true // Find the first incomplete generation of this session, where incomplete means no "results" files while (fs.existsSync(`simulations/${population_data}/gen_${generationCount}`)) { generationCount++ } generationCount-- if (generationCount > 0 && !fs.existsSync(`simulations/${population_data}/gen_${generationCount}/results.csv`)) { generationCount-- } if (noStatSave) { cycleCount++ generationCount = cycleCount } let ofGenerations = (!isUndefined(runGenerations)) ? `of ${runGenerations}` : '' console.log(`\n\n=== Simulating generation ${++generationCount} ${ofGenerations} ===\n`) Backtester.resetMonitor() Backtester.ensureBackfill() iterationCount = 0 let tasks = selectedStrategies.map(v => pools[v]['pool'].population().map(phenotype => { return cb => { phenotype.backtester_generation = iterationCount phenotype.exchangeMarketPair = argv.selector Backtester.trackPhenotype(phenotype) var command let simData = readSimDataFile(iterationCount) if (simData) { if (simData.result) { // Found a complete and cached sim, don't run anything, just forward the results of it phenotype['sim'] = simData.result iterationCount++ return cb(null, simData.result) } else { command = { iteration: iterationCount, commandString: simData.commandString, queryStart: moment(simData.queryStart), queryEnd: moment(simData.queryEnd) } } } if (!command) { // Default flow, build the command to run, and cache it so there's no need to duplicate work when resuming command = Backtester.buildCommand(v, phenotype, `simulations/${population_data}/gen_${generationCount}/sim_${iterationCount}_result.html`) command.iteration = iterationCount writeSimDataFile(iterationCount, JSON.stringify(command)) } iterationCount++ phenotype.minTrades = minimumTrades phenotype.fitnessCalcType = fitnessCalcType Backtester.runCommand(v, phenotype, command, cb) } })).reduce((a, b) => a.concat(b)) Backtester.startMonitor() parallel(tasks, PARALLEL_LIMIT, (err, results) => { Backtester.stopMonitor(`Generation ${generationCount}`) results = results.filter(function (r) { return !!r }) results.sort((a, b) => (Number(a.fitness) < Number(b.fitness)) ? 1 : ((Number(b.fitness) < Number(a.fitness)) ? -1 : 0)) const fields = [ { "label": "Selector", "value": "selector" }, { "label": "Fitness", "value": "fitness" }, { "label": "VS Buy Hold (%)", "value": "vsBuyHold" }, { "label": "Win/Loss Ratio", "value": "wlRatio" }, { "label": "# Trades/Day", "value": "frequency" }, { "label": "Strategy", "value": "strategy" }, { "label": "Order Type", "value": "order_type" }, { "label": "Ending Balance ($)", "value": "endBalance" }, { "label": "Buy Hold ($)", "value": "buyHold" }, { "label": "# Wins", "value": "wins" }, { "label": "# Losses", "value": "losses" }, { "label": "Period", "value": "period_length" }, { "label": "Min Periods", "value": "min_periods" }, { "label": "# Days", "value": "days" }, { "label": "Full Parameters", "value": "params" } ] let json2csvParser = new Json2csvParser({ fields }) let dataCSV = json2csvParser.parse(results) let csvFileName = `simulations/${population_data}/gen_${generationCount}/results.csv` let poolData = {} selectedStrategies.forEach(function (v) { poolData[v] = pools[v]['pool'].population() }) let jsonFileName = `simulations/${population_data}/gen_${generationCount}/results.json` let dataJSON = JSON.stringify(poolData, null, 2) if (!noStatSave) saveGenerationData(csvFileName, jsonFileName, dataCSV, dataJSON) //Display best of the generation console.log('\n\nGeneration\'s Best Results') let bestOverallResult = [] let prefix = './zenbot.sh sim ' selectedStrategies.forEach((v) => { let best = results.find(r => r.strategy == v) let bestCommand if (best) { console.log(`(${best.strategy}) Sim Fitness ${best.fitness}, VS Buy and Hold: ${z(5, (n(best.vsBuyHold).format('0.0') + '%'), ' ').yellow} BuyAndHold Balance: ${z(5, (n(best.buyHold).format('0.000000')), ' ').yellow} End Balance: ${z(5, (n(best.endBalance).format('0.000000')), ' ').yellow}, Wins/Losses ${best.wins}/${best.losses}, ROI ${z(5, (n(best.roi).format('0.000000')), ' ').yellow}.`) bestCommand = generateCommandParams(best) bestOverallResult.push(best) } else { console.log(`(${results[0].strategy}) Result Fitness ${results[0].fitness}, VS Buy and Hold: ${z(5, (n(results[0].vsBuyHold).format('0.0') + '%'), ' ').yellow} BuyAndHold Balance: ${z(5, (n(results[0].buyHold).format('0.000000')), ' ').yellow} End Balance: ${z(5, (n(results[0].endBalance).format('0.000000')), ' ').yellow}, Wins/Losses ${results[0].wins}/${results[0].losses}, ROI ${z(5, (n(results.roi).format('0.000000')), ' ').yellow}.`) bestCommand = generateCommandParams(results[0]) bestOverallResult.push(results[0]) } // prepare command snippet from top result for this strat if (bestCommand != '') { bestCommand = prefix + bestCommand bestCommand = bestCommand + ' --asset_capital=' + argv.asset_capital + ' --currency_capital=' + argv.currency_capital console.log(bestCommand + '\n') } }) bestOverallResult.sort((a, b) => (isUndefined(a.fitness)) ? 1 : (isUndefined(b.fitness)) ? 0 : (a.fitness < b.fitness) ? 1 : (b.fitness < a.fitness) ? -1 : 0) // let bestOverallCommand = generateCommandParams(bestOverallResult[0]) // bestOverallCommand = prefix + bestOverallCommand // bestOverallCommand = bestOverallCommand + ' --asset_capital=' + argv.asset_capital + ' --currency_capital=' + argv.currency_capital saveLaunchFiles(generateLaunchFile, bestOverallResult[0]) if (selectedStrategies.length > 1) { console.log(`(${bestOverallResult[0].strategy}) Best Overall Fitness ${bestOverallResult[0].fitness}, VS Buy and Hold: ${z(5, (n(bestOverallResult[0].vsBuyHold).format('0.00') + '%'), ' ').yellow} BuyAndHold Balance: ${z(5, (n(bestOverallResult[0].buyHold).format('0.000000')), ' ').yellow} End Balance: ${z(5, (n(bestOverallResult[0].endBalance).format('0.000000')), ' ').yellow}, Wins/Losses ${bestOverallResult[0].wins}/${bestOverallResult[0].losses}, ROI ${z(5, (n(bestOverallResult[0].roi).format('0.000000')), ' ').yellow}.`) } selectedStrategies.forEach((v) => { pools[v]['pool'] = pools[v]['pool'].evolve() }) if (!isUndefined(runGenerations) && runGenerations <= generationCount) { process.exit() } generationProcessing = false }) } console.log(`\n--==${VERSION}==--`) console.log(new Date().toUTCString() + '\n') simArgs = Object.assign({}, argv) if (!simArgs.selector) { simArgs.selector = 'bitfinex.ETH-USD' } if (!simArgs.filename) { simArgs.filename = 'none' } if (simArgs.help || !(simArgs.use_strategies)) { console.log('--use_strategies=,, Min one strategy, can include more than one') console.log('--population_data= filename used for continueing backtesting from previous run') console.log('--generateLaunch=| will generate .sh and .bat file using the best generation discovered') console.log('--population= populate per strategy') console.log('--maxCores= maximum processes to execute at a time default is # of cpu cores in system') console.log('--selector= ') console.log('--asset_capital= amount coin to start sim with ') console.log('--currency_capital= amount of capital/base currency to start sim with') console.log('--days= amount of days to use when backfilling') console.log('--noStatSave=|') console.log('--runGenerations= if used run this number of generations, will be shown 1 less due to generations starts at 0') console.log('--minTrades= Minimum wins before generation is considured fit to evolve') console.log('--fitnessCalcType= Default: Classic.') console.log(' wl will score the highes for wins and losses, profit does not care about wins and losses only the higest end balance,') console.log(' classic uses original claculation / profitwl tries to get the highest profit using the lowest win/loss ratio') process.exit(0) } delete simArgs.use_strategies delete simArgs.population_data delete simArgs.population delete simArgs['$0'] // This comes in to argv all by itself delete simArgs['_'] // This comes in to argv all by itself if (simArgs.maxCores) { if (simArgs.maxCores < 1) PARALLEL_LIMIT = 1 else PARALLEL_LIMIT = simArgs.maxCores } fitnessCalcType = 'classic' if (simArgs.fitnessCalcType) { if (simArgs.fitnessCalcType == 'classic') fitnessCalcType = 'classic' if (simArgs.fitnessCalcType == 'wl') fitnessCalcType = 'wl' if (simArgs.fitnessCalcType == 'profit') fitnessCalcType = 'profit' if (simArgs.fitnessCalcType == 'profitwl') fitnessCalcType = 'profitwl' } if (!isUndefined(simArgs.runGenerations)) { if (simArgs.runGenerations) { runGenerations = simArgs.runGenerations - 1 } } let generateLaunchFile = (simArgs.generateLaunch) ? true : false noStatSave = (simArgs.noStatSave) ? true : false let strategyName = (argv.use_strategies) ? argv.use_strategies : 'all' populationSize = (argv.population) ? argv.population : 100 minimumTrades = (argv.minTrades) ? argv.minTrades : 0 //floatScanWindow = (argv.floatScanWindow) ? argv.floatScanWindow : false ignoreLaunchFitness = (argv.ignoreLaunchFitness) ? argv.ignoreLaunchFitness : false population_data = argv.population_data || `backtest.${simArgs.selector.toLowerCase()}.${moment().format('YYYYMMDDHHmmss')}` console.log(`Backtesting strategy ${strategyName} ...\n`) console.log(`Creating population of ${populationSize} ...\n`) selectedStrategies = (strategyName === 'all') ? allStrategyNames() : strategyName.split(',') Backtester.deLint() for (var i = 0; i < selectedStrategies.length; i++) { let v = selectedStrategies[i] let strategyPool = pools[v] = {} let strategyData = require(path.resolve(__dirname, `../../extensions/strategies/${v}/strategy`)) let strategyPhenotypes = strategyData.phenotypes if (strategyPhenotypes) { let evolve = true let population = [] for (var i2 = population.length; i2 < populationSize; ++i2) { var lPheno = Phenotypes.create(strategyPhenotypes) population.push(lPheno) evolve = false } strategyPool['config'] = { mutationFunction: function (phenotype) { return Phenotypes.mutation(phenotype, strategyPhenotypes) }, crossoverFunction: function (phenotypeA, phenotypeB) { return Phenotypes.crossover(phenotypeA, phenotypeB, strategyPhenotypes) }, fitnessFunction: Phenotypes.fitness, doesABeatBFunction: Phenotypes.competition, population: population, populationSize: populationSize } strategyPool['pool'] = GeneticAlgorithmCtor(strategyPool.config) if (evolve) { strategyPool['pool'].evolve() } } else { if (strategyName === 'all') { // skip it selectedStrategies.splice(i, 1) i-- } else { console.log(`No phenotypes definition found for strategy ${v}`) process.exit(1) } } } // BEGIN - exitHandler var exitHandler = function (options, exitErr) { if (generationCount && options.cleanup && (isUndefined(runGenerations) || runGenerations !== generationCount)) { console.log('Resume this backtest later with:') var darwin_args = process.argv.slice(2, process.argv.length) var hasPopData = false var popDataArg = `--population_data=${population_data}` darwin_args.forEach(function (arg) { if (arg === popDataArg) { hasPopData = true } }) if (!hasPopData) { darwin_args.push(popDataArg) } console.log(`./scripts/genetic_backtester/darwin.js ${darwin_args.join(' ')}`) } if (exitErr) console.log(exitErr.stack || exitErr) if (options.exit) process.exit() } process.on('exit', exitHandler.bind(null, { cleanup: true })) //catches ctrl+c event process.on('SIGINT', exitHandler.bind(null, { exit: true })) // catches "kill pid" (for example: nodemon restart) process.on('SIGUSR1', exitHandler.bind(null, { exit: true })) process.on('SIGUSR2', exitHandler.bind(null, { exit: true })) //catches uncaught exceptions process.on('uncaughtException', exitHandler.bind(null, { exit: true })) // END - exitHandler Backtester.init({ simArgs: simArgs, simTotalCount: populationSize * selectedStrategies.length, parallelLimit: PARALLEL_LIMIT, writeFile: writeSimDataFile }) setInterval(() => { if (generationProcessing == false) simulateGeneration(generateLaunchFile) }, 1000) ================================================ FILE: scripts/genetic_backtester/package.json ================================================ { "name": "zenbot4_auto_backtester", "version": "0.2.0", "description": "Parallel simulation runner with CSV results", "dependencies": { "geneticalgorithm": "git+https://github.com/panchishin/geneticalgorithm.git", "json2csv": "^4.5.4", "round-precision": "^1.0.0", "run-parallel-limit": "^1.1.0", "shelljs": "^0.8.5", "yargs": "^16.2.0", "strip-ansi": "^7.0.1" } } ================================================ FILE: stats/index.html ================================================ cexio.ETH-USD - zenbot 4.0.5 trade result
last balance: 358.45244248 (-0.58%)
buy hold: 358.42887441 (-0.59%)
vs. buy hold: 0.01%
0 trades over 1 days (avg 0.00 trades/day)
================================================ FILE: stats/readme.md ================================================ ## Stats HTML Outputs from trades will be placed here! ================================================ FILE: templates/dashboard.ejs ================================================ <%= asset.toUpperCase() %>/<%= currency.toUpperCase() %> on <%= exchange.name.toUpperCase() %> - Dashboard

Dashboard

Current Market

  • Price
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(period.close) %> <%= asset.toUpperCase() %>
<% if (typeof quote != "undefined") { %>
  • ASK
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(quote.ask) %> <%= asset.toUpperCase() %>
  • BID
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(quote.bid) %> <%= asset.toUpperCase() %>
<% } %>

Capital

  • Asset
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 8}).format(balance.asset) %> <%= asset.toUpperCase() %>
<% if (typeof deposit != "undefined") { %>
  • Deposit
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 8}).format(balance.deposit) %> <%= currency.toUpperCase() %>
<% } %>
  • Currency
  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 8}).format(balance.currency) %> <%= currency.toUpperCase() %>
<% if (typeof stats != "undefined") { %>

Last balance (<%= new Intl.NumberFormat("en-US", {style: "percent", minimumFractionDigits: 2, maximumFractionDigits: 2}).format((parseFloat(stats.profit)/100)-(parseFloat(stats.buy_hold_profit)/100) ) %> vs buy hold)

  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(stats.tmp_balance) %> <%= currency.toUpperCase() %>
  • <%= stats.profit %> of profit

Buy hold

  • <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(stats.buy_hold) %> <%= currency.toUpperCase() %>
  • <%= stats.buy_hold_profit %> of profit

Trades per day

  • <%= stats.trade_per_day %>
  • <%= my_trades.length %> trade<% if (my_trades.length != 1) { %>s<% } %> over <%= day_count %> day<% if (day_count != 1) { %>s<% } %>
<% if (typeof stats.error_rate != "undefined") { %>

Error Rate

  • <%= stats.error_rate %>
  • Win/Loss: <%= stats.win %>/<%= stats.losses %>
<% } %> <% } %>

<%= exchange.name.toUpperCase() %> <%= asset.toUpperCase() %>/<%= currency.toUpperCase() %> Trade chart

My trades

<% if (typeof buy_order != "undefined") { %> <% } %> <% if (typeof sell_order != "undefined") { %> <% } %> <% if (my_trades) { %> <% my_trades.sort(function(a,b){return a.time > b.time ? -1 : 1;}).forEach(function(trade){ %> <% }); %> <% } %> <% if (my_prev_trades) { %> <% my_prev_trades.reverse().forEach(function(trade){ %> <% }); %> <% } %> <% if (!(typeof buy_order != "undefined" || typeof sell_order != "undefined") && !my_trades) { %> <% } %>
TYPE AMOUNT PRICE TOTAL FEE SLIPPAGE DATE EXECUTION TIME PROFIT
BUY <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(buy_order.size) %> <%= asset.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(buy_order.price) %> <%= currency.toUpperCase() %> - - - <%= moment(buy_order.time).format('YYYY-MM-DD HH:mm:ss') %> Waiting -
SELL <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(sell_order.size) %> <%= asset.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(sell_order.price) %> <%= currency.toUpperCase() %> - - - <%= moment(sell_order.time).format('YYYY-MM-DD HH:mm:ss') %> Waiting -
<%= trade.type.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(trade.size) %> <%= asset.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(trade.price) %> <%= currency.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(trade.size * trade.price) %> <%= currency.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 8}).format(trade.fee) %> <% if (trade.type == "buy") { %> <%= asset.toUpperCase() %> <% } else { %> <%= currency.toUpperCase() %> <% } %> <%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 4, maximumFractionDigits: 4}).format(trade.slippage) %> <%= moment(trade.time).format('YYYY-MM-DD HH:mm:ss') %> <%= moment.duration(trade.execution_time).humanize() %> <% if (trade.profit != null) { %><%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 2}).format(trade.profit) %><% } else { %>-<% } %>
<%= trade.type.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 8, maximumFractionDigits: 8}).format(trade.size) %> <%= asset.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(trade.price) %> <%= currency.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 7}).format(trade.size * trade.price) %> <%= currency.toUpperCase() %> <%= new Intl.NumberFormat("en-US", {useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 8}).format(trade.fee) %> <% if (trade.type == "buy") { %> <%= asset.toUpperCase() %> <% } else { %> <%= currency.toUpperCase() %> <% } %> <%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 4, maximumFractionDigits: 4}).format(trade.slippage) %> <%= moment(trade.time).format('YYYY-MM-DD HH:mm:ss') %> <%= moment.duration(trade.execution_time).humanize() %> <% if (trade.profit) { %><%= new Intl.NumberFormat("en-US", {style: "percent", useGrouping: false, minimumFractionDigits: 2, maximumFractionDigits: 2}).format(trade.profit) %><% } else { %>-<% } %>
There is no trades at the moment

CoinMarketCap Data

RANK NAME PRICE (USD) CHANGE 1H CHANGE 24H CHANGE 7D
<%= (new Date()).getFullYear() %> © zenbot
================================================ FILE: templates/dashboard_assets/css/animate.css ================================================ @charset "UTF-8";/*! * animate.css -http://daneden.me/animate * Version - 3.5.1 * Licensed under the MIT license - http://opensource.org/licenses/MIT * * Copyright (c) 2016 Daniel Eden */.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.flipOutX,.animated.flipOutY,.animated.bounceIn,.animated.bounceOut{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{from,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{from,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{from,to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{from,to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}to{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}to{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{from,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{from,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{from,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{from,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@keyframes fadeOut{from{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{from{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{from{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp} ================================================ FILE: templates/dashboard_assets/css/colors/default.css ================================================ @import url(https://fonts.googleapis.com/css?family=Rubik:300,400,500,700,900); /*Theme Colors*/ /*bootstrap Color*/ /*Normal Color*/ /*Border radius*/ /*Preloader*/ .preloader { width: 100%; height: 100%; top: 0px; position: fixed; z-index: 99999; background: #fff; } .preloader .cssload-speeding-wheel { position: absolute; top: calc(50% - 3.5px); left: calc(50% - 3.5px); } /*Just change your choise color here its theme Colors*/ body { background: #fff; } .top-left-part { background: #fff; } .top-left-part .dark-logo { display: none; } .top-left-part .light-logo { display: inline-block; } /*Top Header Part*/ .logo i { color: #ffffff; } .navbar-header { background: #2f323e; } .navbar-top-links > li > a { color: #ffffff; } .sidebar .sidebar-head { background: #ffffff; } .sidebar .sidebar-head h3 { color: #686868; } /*Right panel*/ .right-sidebar .rpanel-title { background: #41b3f9; } /*Bread Crumb*/ .bg-title .breadcrumb .active { color: #41b3f9; } /*Sidebar*/ .sidebar { background: #fff; box-shadow: 1px 0px 20px rgba(0, 0, 0, 0.08); } .sidebar .label-custom { background: #01c0c8; } #side-menu li a { color: #54667a; } #side-menu li a { color: #54667a; border-left: 0px solid #fff; } #side-menu > li > a { border-left: 3px solid transperant; } #side-menu > li > a:hover, #side-menu > li > a:focus { background: rgba(0, 0, 0, 0.07); } #side-menu > li > a.active { background: transperant; color: #54667a; border-left: 3px solid #41b3f9; font-weight: 500; } #side-menu ul > li > a:hover { color: #41b3f9; } #side-menu ul > li > a.active { color: #54667a; font-weight: 500; } .user-profile .user-pro-body .u-dropdown { color: #54667a; } /*themecolor*/ .bg-theme { background-color: #707cd2 !important; } .bg-theme-dark { background-color: #41b3f9 !important; } /*Button*/ .btn-custom { background: #41b3f9; border: 1px solid #41b3f9; color: #ffffff; } .btn-custom:hover { background: #41b3f9; opacity: 0.8; color: #ffffff; border: 1px solid #41b3f9; } /*Custom tab*/ .customtab li.active a, .customtab li.active a:hover, .customtab li.active a:focus { border-bottom: 2px solid #41b3f9; color: #41b3f9; } .tabs-vertical li.active a, .tabs-vertical li.active a:hover, .tabs-vertical li.active a:focus { background: #41b3f9; border-right: 2px solid #41b3f9; } /*Nav-pills*/ .nav-pills > li.active > a, .nav-pills > li.active > a:focus, .nav-pills > li.active > a:hover { background: #41b3f9; color: #ffffff; } /*Extra css*/ .bg-theme { background-color: #41b3f9 !important; } .panel-themecolor, .panel-theme { border-color: #41b3f9; } .panel-themecolor .panel-heading, .panel-theme .panel-heading { border-color: #41b3f9; color: white; background-color: #41b3f9; } .panel-themecolor .panel-heading a, .panel-theme .panel-heading a { color: #ffffff; } .panel-themecolor .panel-heading a:hover, .panel-theme .panel-heading a:hover { color: rgba(255, 255, 255, 0.5); } .panel-themecolor a, .panel-theme a { color: #41b3f9; } .panel-themecolor a:hover, .panel-theme a:hover { color: #0791e6; } ================================================ FILE: templates/dashboard_assets/css/spinners.css ================================================ .preloader{ position: relative; margin: 0 auto; width: 100px; } .preloader:before{ content: ''; display: block; padding-top: 100%; } .circular { animation: rotate 2s linear infinite; height: 50px; transform-origin: center center; width: 50px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; } .path { stroke-dasharray: 1, 200; stroke-dashoffset: 0; animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite; stroke-linecap: round; } @keyframes rotate { 100% { transform: rotate(360deg); } } @keyframes dash { 0% { stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { stroke-dasharray: 89, 200; stroke-dashoffset: -35px; } 100% { stroke-dasharray: 89, 200; stroke-dashoffset: -124px; } } @keyframes color { 100%, 0% { stroke: #d62d20; } 40% { stroke: #0057e7; } 66% { stroke: #008744; } 80%, 90% { stroke: #ffa700; } } ================================================ FILE: templates/dashboard_assets/css/style.css ================================================ @import url(https://fonts.googleapis.com/css?family=Rubik:300,400,500,700,900); @import url(https://coinmarketcap.com/static/public/sprites/all_views_market-cap-by-circulating-supply_0.css); @import "spinners.css"; .preloader { width: 100%; height: 100%; top: 0; position: fixed; z-index: 99999; background: #fff } .preloader .cssload-speeding-wheel { position: absolute; top: calc(50% - 3.5px); left: calc(50% - 3.5px) } * { outline: 0!important } body { background: #2f323e; font-family: Rubik, sans-serif; margin: 0; overflow-x: hidden; color: #313131; font-weight: 300 } html { position: relative; min-height: 100%; background: #fff } h1, h2, h3, h4, h5, h6 { color: #313131; font-family: Rubik, sans-serif; margin: 10px 0; font-weight: 300 } h1 { line-height: 48px; font-size: 36px } h2 { line-height: 36px; font-size: 24px } h3 { line-height: 30px; font-size: 21px } h4 { line-height: 22px; font-size: 18px } h5 { font-size: 16px; font-size: 14px } .dn { display: none } .db { display: block } .light_op_text { color: rgba(255, 255, 255, .5) } blockquote { border-left: 5px solid #2cabe3!important; border: 1px solid rgba(120, 130, 140, .13) } p { line-height: 1.6 } b { font-weight: 500 } a:active, a:focus, a:hover { outline: 0; text-decoration: none } .clear { clear: both } .font-12 { font-size: 12px } hr { border-color: rgba(120, 130, 140, .13) } .b-t { border-top: 1px solid rgba(120, 130, 140, .13) } .b-b { border-bottom: 1px solid rgba(120, 130, 140, .13) } .b-l { border-left: 1px solid rgba(120, 130, 140, .13) } .b-r { border-right: 1px solid rgba(120, 130, 140, .13) } .b-all { border: 1px solid rgba(120, 130, 140, .13) } .b-none { border: 0!important } .max-height { height: 310px; overflow: auto } .p-0 { padding: 0!important } .p-10 { padding: 10px!important } .p-20 { padding: 20px!important } .p-30 { padding: 30px!important } .p-l-0 { padding-left: 0!important } .p-l-10 { padding-left: 10px!important } .p-l-20 { padding-left: 20px!important } .p-l-30 { padding-left: 30px!important } .p-r-0 { padding-right: 0!important } .p-r-10 { padding-right: 10px!important } .p-r-20 { padding-right: 20px!important } .p-r-30 { padding-right: 30px!important } .p-r-40 { padding-right: 40px!important } .p-t-0 { padding-top: 0!important } .p-t-10 { padding-top: 10px!important } .p-t-20 { padding-top: 20px!important } .p-t-30 { padding-top: 30px!important } .p-b-0 { padding-bottom: 0!important } .p-b-10 { padding-bottom: 10px!important } .p-b-20 { padding-bottom: 20px!important } .p-b-30 { padding-bottom: 30px!important } .p-b-40 { padding-bottom: 40px!important } .m-0 { margin: 0!important } .m-l-5 { margin-left: 5px!important } .m-l-10 { margin-left: 10px!important } .m-l-15 { margin-left: 15px!important } .m-l-20 { margin-left: 20px!important } .m-l-30 { margin-left: 30px!important } .m-l-40 { margin-left: 40px!important } .m-r-5 { margin-right: 5px!important } .m-r-10 { margin-right: 10px!important } .m-r-15 { margin-right: 15px!important } .m-r-20 { margin-right: 20px!important } .m-r-30 { margin-right: 30px!important } .m-r-40 { margin-right: 40px!important } .m-t-5 { margin-top: 5px!important } .m-t-0 { margin-top: 0!important } .m-t-10 { margin-top: 10px!important } .m-t-15 { margin-top: 15px!important } .m-t-20 { margin-top: 20px!important } .m-t-30 { margin-top: 30px!important } .m-t-40 { margin-top: 40px!important } .m-b-0 { margin-bottom: 0!important } .m-b-5 { margin-bottom: 5px!important } .m-b-10 { margin-bottom: 10px!important } .m-b-15 { margin-bottom: 15px!important } .m-b-20 { margin-bottom: 20px!important } .m-b-30 { margin-bottom: 30px!important } .m-b-40 { margin-bottom: 40px!important } .vt { vertical-align: top } .vb { vertical-align: bottom } .font-bold { font-weight: 700 } .font-medium { font-weight: 500 } .font-normal { font-weight: 400 } .font-light { font-weight: 300 } .pull-in { margin-left: -15px; margin-right: -15px } .b-0 { border: none!important } .vertical-middle, .vm { vertical-align: middle } .mdi { font-size: 17px } .bx-shadow { -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1); box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1) } .mx-box { max-height: 380px; min-height: 380px } .thumb-sm { height: 32px; width: 32px } .thumb-md { height: 48px; width: 48px } .thumb-lg { height: 88px; width: 88px } .txt-oflo { text-overflow: ellipsis; overflow: hidden; white-space: nowrap } .di { display: inline-block } .get-code { color: #263238; cursor: pointer; border-radius: 100%; background: #fff; padding: 4px 5px; font-size: 10px; margin: 0 5px; vertical-align: middle } .badge { text-transform: uppercase; font-weight: 600; padding: 3px 5px; font-size: 12px; margin-top: 1px; background-color: #fb4 } .badge-xs { font-size: 9px } .badge-sm, .badge-xs { -webkit-transform: translate(0, -2px); -ms-transform: translate(0, -2px); -o-transform: translate(0, -2px); transform: translate(0, -2px) } .badge-success { background-color: #7ace4c } .badge-info { background-color: #41b3f9 } .badge-warning { background-color: #fb4 } .badge-danger { background-color: #f33155 } .badge-purple { background-color: #707cd2 } .badge-red { background-color: #f33155 } .badge-inverse { background-color: #4c5667 } .notify { position: relative; margin-top: -30px } .notify .heartbit { position: absolute; top: -20px; right: -16px; height: 25px; width: 25px; z-index: 10; border: 5px solid #f33155; border-radius: 70px; -moz-animation: heartbit 1s ease-out; -moz-animation-iteration-count: infinite; -o-animation: heartbit 1s ease-out; -o-animation-iteration-count: infinite; -webkit-animation: heartbit 1s ease-out; -webkit-animation-iteration-count: infinite; animation-iteration-count: infinite } .notify .point { width: 6px; height: 6px; -webkit-border-radius: 30px; -moz-border-radius: 30px; border-radius: 30px; background-color: #f33155; position: absolute; right: -6px; top: -10px } @-moz-keyframes heartbit { 0% { -moz-transform: scale(0); opacity: 0 } 25% { -moz-transform: scale(.1); opacity: .1 } 50% { -moz-transform: scale(.5); opacity: .3 } 75% { -moz-transform: scale(.8); opacity: .5 } 100% { -moz-transform: scale(1); opacity: 0 } } @-webkit-keyframes heartbit { 0% { -webkit-transform: scale(0); opacity: 0 } 25% { -webkit-transform: scale(.1); opacity: .1 } 50% { -webkit-transform: scale(.5); opacity: .3 } 75% { -webkit-transform: scale(.8); opacity: .5 } 100% { -webkit-transform: scale(1); opacity: 0 } } .text-white { color: #fff } .text-danger { color: #f33155 } .text-muted { color: #8d9ea7 } .text-warning { color: #fb4 } .text-success { color: #7ace4c } .text-info { color: #41b3f9 } .text-inverse { color: #4c5667 } .text-blue { color: #02bec9 } .text-purple { color: #707cd2 } .text-primary { color: #7460ee } .text-megna { color: #01c0c8 } .text-dark { color: #313131!important } .fw-500 { font-weight: 500 } .bg-primary { background-color: #7460ee!important } .bg-success { background-color: #7ace4c!important } .bg-info { background-color: #41b3f9!important } .bg-warning { background-color: #fb4!important } .bg-danger, .bg-theme-alt { background-color: #f33155!important } .bg-theme { background-color: #2cabe3!important } .bg-theme-dark { background-color: #4f5467!important } .bg-inverse { background-color: #4c5667!important } .bg-purple { background-color: #707cd2!important } .bg-white { background-color: #fff!important } .bg-light { background-color: #e4e7ea!important } .bg-extralight { background-color: #f7fafc!important } .label { letter-spacing: .05em; border-radius: 60px; padding: 4px 12px 3px; font-weight: 500 } .label-rouded, .label-rounded { border-radius: 60px; padding: 4px 12px 3px; font-weight: 500 } .label-custom { background-color: #01c0c8 } .label-success { background-color: #7ace4c } .label-info { background-color: #41b3f9 } .label-warning { background-color: #fb4 } .label-danger { background-color: #f33155 } .label-megna { background-color: #01c0c8 } .label-primary { background-color: #7460ee } .label-purple { background-color: #707cd2 } .label-red { background-color: #f33155 } .label-inverse { background-color: #4c5667 } .label-white { background-color: #fff } .label-default { background-color: #e4e7ea } .dropdown-menu { border: 1px solid rgba(120, 130, 140, .13); border-radius: 0; box-shadow: 0 3px 12px rgba(0, 0, 0, .05)!important; -webkit-box-shadow: 0!important; -moz-box-shadow: 0!important; padding-bottom: 8px; margin-top: 0 } .dropdown-menu>li>a { padding: 9px 20px } .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover { background: #f7fafc } .navbar-top-links .progress { margin-bottom: 6px } label { font-weight: 500 } .btn { border-radius: 3px } .form-control { background-color: #fff; border: 1px solid #e4e7ea; border-radius: 0; box-shadow: 4px; color: #565656; height: 38px; max-width: 100%; padding: 7px 12px; transition: all 300ms linear 0s } .form-control:focus { box-shadow: none; border-color: #263238 } .input-sm { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5 } .input-lg { height: 44px; padding: 5px 10px; font-size: 18px } .bootstrap-tagsinput { border: 1px solid #e4e7ea; border-radius: 0; box-shadow: none; display: block; padding: 7px 12px } .bootstrap-touchspin .input-group-btn-vertical>.btn { padding: 9px 10px } .bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down, .bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up { border-radius: 0 } .input-group-btn .btn { padding: 8px 12px } .form-group, .form-horizontal .form-group { margin-bottom: 25px } .list-group-item, .list-group-item:first-child, .list-group-item:last-child { border-radius: 0; border-color: rgba(120, 130, 140, .13) } .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { background: #41b3f9; border-color: #41b3f9 } .list-task .list-group-item, .list-task .list-group-item:first-child { border-radius: 0; border: 0 } .list-task .list-group-item:last-child { border-radius: 0; border: 0 } .media { border: 1px solid rgba(120, 130, 140, .13); margin-bottom: 10px; padding: 15px } .media .media-heading { font-weight: 500 } .well, pre { background: #fff; border-radius: 0 } .nav-tabs>li>a { border-radius: 0; color: #263238 } .nav-tabs>li>a:focus, .nav-tabs>li>a:hover { background: #fff } .modal-content { border-radius: 0; box-shadow: 0 5px 15px rgba(0, 0, 0, .1) } .alert { border-radius: 0 } .carousel-control { width: 8% } .carousel-control span { position: absolute; top: 50%; z-index: 5; display: inline-block; font-size: 30px } .popover { border-radius: 0; z-index: 100 } .popover-title { padding: 5px 14px } .container-fluid { padding-left: 25px; padding-right: 25px; padding-bottom: 15px } .btn-group-vertical>.btn:first-child:not(:last-child), .btn-group-vertical>.btn:last-child:not(:first-child) { border-radius: 0 } .table-responsive { overflow-y: hidden } .pagination>li:first-child>a, .pagination>li:first-child>span { border-bottom-left-radius: 0; border-top-left-radius: 0 } .pagination>li:last-child>a, .pagination>li:last-child>span { border-bottom-right-radius: 0; border-top-right-radius: 0 } .pagination>li>a, .pagination>li>span { color: #263238 } .pagination>li>a:focus, .pagination>li>a:hover, .pagination>li>span:focus, .pagination>li>span:hover { background-color: #e4e7ea } .pagination-split li { margin-left: 5px; display: inline-block; float: left } .pagination-split li:first-child { margin-left: 0 } .pagination-split li a { -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0 } .pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover, .pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover { background-color: #2cabe3; border-color: #2cabe3 } .pager li>a, .pager li>span { -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; color: #263238 } .table-box { display: table; width: 100% } .cell { display: table-cell; vertical-align: middle } .jqstooltip { width: auto!important; height: auto!important } #wrapper { width: 100% } #page-wrapper { padding: 0 0 60px; min-height: 568px; background: #edf1f5 } .footer { bottom: 0; color: #58666e; left: 240px; padding: 20px 30px; position: absolute; right: 0; background: #fff } .bg-title { background: #fff; overflow: hidden; padding: 15px 10px 9px; margin-bottom: 25px; margin-left: -25.5px; margin-right: -25.5px } .bg-title h4 { text-transform: uppercase; font-size: 14px; font-weight: 500; margin-top: 6px } .bg-title .breadcrumb { background: 0 0; margin-bottom: 0; float: right; padding: 0; margin-top: 8px } .bg-title .breadcrumb a { color: rgba(0, 0, 0, .5) } .bg-title .breadcrumb a:hover { color: #000 } .bg-title .breadcrumb .active { color: #2cabe3 } .logo b { height: 60px; float: left; padding-left: 10px; width: auto; line-height: 59px; text-align: center } .logo i { color: #fff } .top-left-part { width: 240px; float: left; border-right: 1px solid rgba(0, 0, 0, .08) } .top-left-part a { color: #fff; line-height: 59px; font-size: 18px; padding-left: 10px; text-transform: uppercase } .top-left-part .light-logo { display: none } .navbar-header { width: 100%; background: #3c4451; border: 0 } .navbar-default { border: 0 } .navbar-top-links { margin-right: 0 } .navbar-top-links .badge { position: absolute; right: 6px; top: 15px } .navbar-top-links>li { float: left } .navbar-top-links>li>a { color: #fff; padding: 0 14px; line-height: 60px; min-height: 60px } .navbar-top-links>li>a:hover { background: rgba(0, 0, 0, .1) } .navbar-top-links>li>a:focus { background: rgba(0, 0, 0, 0) } .nav .open>a, .nav .open>a:focus, .nav .open>a:hover { background: rgba(255, 255, 255, .2) } .navbar-top-links .dropdown-menu li { display: block } .navbar-top-links .dropdown-menu li:last-child { margin-right: 0 } .navbar-top-links .dropdown-menu li a div { white-space: normal } .navbar-top-links .dropdown-alerts, .navbar-top-links .dropdown-messages, .navbar-top-links .dropdown-tasks { width: 310px; min-width: 0 } .navbar-top-links .dropdown-user { right: 0; left: auto; width: 280px } .navbar-top-links .dropdown-user .dw-user-box { padding: 15px } .navbar-top-links .dropdown-user .dw-user-box .u-img { width: 80px; display: inline-block; vertical-align: top } .navbar-top-links .dropdown-user .dw-user-box .u-img img { width: 100%; border-radius: 5px } .navbar-top-links .dropdown-user .dw-user-box .u-text { display: inline-block; padding-left: 10px } .navbar-top-links .dropdown-user .dw-user-box .u-text h4 { margin: 0 } .navbar-top-links .dropdown-user .dw-user-box .u-text p { margin-bottom: 3px } .navbar-header .navbar-toggle { float: none; padding: 0 15px; line-height: 60px; border: 0; color: rgba(255, 255, 255, .5); margin: 0; display: inline-block; border-radius: 0 } .navbar-header .navbar-toggle:focus, .navbar-header .navbar-toggle:hover { background: rgba(0, 0, 0, .3); color: #fff } .app-search { position: relative; margin: 0 } .app-search a { position: absolute; top: 20px; right: 10px; color: #4c5667 } .app-search .form-control, .app-search .form-control:focus { border: none; font-size: 13px; color: #4c5667; padding-left: 20px; padding-right: 40px; background: rgba(255, 255, 255, .9); box-shadow: none; height: 30px; font-weight: 600; width: 180px; display: inline-block; line-height: 30px; margin-top: 15px; border-radius: 40px; transition: .5s ease-out } .app-search .form-control::-moz-placeholder { color: #4c5667; opacity: .5 } .app-search .form-control::-webkit-input-placeholder { color: #4c5667; opacity: .5 } .app-search .form-control::-ms-placeholder { color: #4c5667; opacity: .5 } .nav-small-cap { color: #a6afbb; cursor: default; font-weight: 500; text-transform: uppercase; font-size: 13px; letter-spacing: .035em; padding: 12px 15px!important; pointer-events: none; margin: 20px 0 0 -15px } .profile-pic { padding: 0 20px; line-height: 50px } .profile-pic img { margin-right: 10px } .drop-title { border-bottom: 1px solid rgba(0, 0, 0, .1); color: #263238; font-size: 15px; font-weight: 600; padding: 11px 20px 15px } .btn-outline { color: inherit; background-color: transparent; transition: all .5s } .btn-rounded { border-radius: 60px } .btn-custom, .btn-custom.disabled { background: #2cabe3; border: 1px solid #2cabe3; color: #fff } .btn-custom.disabled.focus, .btn-custom.disabled:focus, .btn-custom.disabled:hover, .btn-custom.focus, .btn-custom:focus, .btn-custom:hover { background: #2cabe3; opacity: .8; color: #fff; border: 1px solid #2cabe3 } .btn-primary, .btn-primary.disabled { background: #7460ee; border: 1px solid #7460ee } .btn-primary.disabled.focus, .btn-primary.disabled:focus, .btn-primary.disabled:hover, .btn-primary.focus, .btn-primary:focus, .btn-primary:hover { background: #7460ee; opacity: .8; border: 1px solid #7460ee } .btn-success, .btn-success.disabled { background: #7ace4c; border: 1px solid #7ace4c } .btn-success.disabled.focus, .btn-success.disabled:focus, .btn-success.disabled:hover, .btn-success.focus, .btn-success:focus, .btn-success:hover { background: #7ace4c; opacity: .8; border: 1px solid #7ace4c } .btn-info, .btn-info.disabled { background: #41b3f9; border: 1px solid #41b3f9 } .btn-info.disabled.focus, .btn-info.disabled:focus, .btn-info.disabled:hover, .btn-info.focus, .btn-info:focus, .btn-info:hover { background: #41b3f9; opacity: .8; border: 1px solid #41b3f9 } .btn-warning, .btn-warning.disabled { background: #fb4; border: 1px solid #fb4 } .btn-warning.disabled.focus, .btn-warning.disabled:focus, .btn-warning.disabled:hover, .btn-warning.focus, .btn-warning:focus, .btn-warning:hover { background: #fb4; opacity: .8; border: 1px solid #fb4 } .btn-danger, .btn-danger.disabled { background: #f33155; border: 1px solid #f33155 } .btn-danger.disabled.focus, .btn-danger.disabled:focus, .btn-danger.disabled:hover, .btn-danger.focus, .btn-danger:focus, .btn-danger:hover { background: #f33155; opacity: .8; border: 1px solid #f33155 } .btn-default, .btn-default.disabled { background: #e4e7ea; border: 1px solid #e4e7ea } .btn-default.disabled.focus, .btn-default.disabled:focus, .btn-default.disabled:hover, .btn-default.focus, .btn-default:focus, .btn-default:hover { opacity: .8; border: 1px solid #e4e7ea; background: #e4e7ea } .btn-default.btn-outline { background-color: #fff } .btn-default.btn-outline.focus, .btn-default.btn-outline:focus, .btn-default.btn-outline:hover { background: #e4e7ea } .btn-primary.btn-outline { color: #7460ee; background-color: #fff } .btn-primary.btn-outline.focus, .btn-primary.btn-outline:focus, .btn-primary.btn-outline:hover { background: #7460ee; color: #fff } .btn-success.btn-outline { color: #7ace4c; background-color: transparent } .btn-success.btn-outline.focus, .btn-success.btn-outline:focus, .btn-success.btn-outline:hover { background: #7ace4c; color: #fff } .btn-info.btn-outline { color: #41b3f9; background-color: transparent } .btn-info.btn-outline.focus, .btn-info.btn-outline:focus, .btn-info.btn-outline:hover { background: #41b3f9; color: #fff } .btn-warning.btn-outline { color: #fb4; background-color: transparent } .btn-warning.btn-outline.focus, .btn-warning.btn-outline:focus, .btn-warning.btn-outline:hover { background: #fb4; color: #fff } .btn-danger.btn-outline { color: #f33155; background-color: transparent } .btn-danger.btn-outline.focus, .btn-danger.btn-outline:focus, .btn-danger.btn-outline:hover { background: #f33155; color: #fff } .button-box .btn { margin: 0 8px 8px 0 } .btn-danger.btn-outline:hover, .btn-info.btn-outline:hover, .btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-warning.btn-outline:hover { color: #fff } .btn-label { background: rgba(0, 0, 0, .05); display: inline-block; margin: -6px 12px -6px -14px; padding: 7px 15px } .btn-facebook { color: #fff!important; background-color: #3b5998!important } .btn-twitter { color: #fff!important; background-color: #55acee!important } .btn-linkedin { color: #fff!important; background-color: #007bb6!important } .btn-dribbble { color: #fff!important; background-color: #ea4c89!important } .btn-googleplus { color: #fff!important; background-color: #dd4b39!important } .btn-instagram { color: #fff!important; background-color: #3f729b!important } .btn-pinterest { color: #fff!important; background-color: #cb2027!important } .btn-dropbox { color: #fff!important; background-color: #007ee5!important } .btn-flickr { color: #fff!important; background-color: #ff0084!important } .btn-tumblr { color: #fff!important; background-color: #32506d!important } .btn-skype { color: #fff!important; background-color: #00aff0!important } .btn-youtube { color: #fff!important; background-color: #b00!important } .btn-github { color: #fff!important; background-color: #171515!important } .btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, .btn-primary.focus, .btn-primary.focus:active, .btn-primary:active:focus, .btn-primary:active:hover, .btn-primary:focus, .open>.dropdown-toggle.btn-primary.focus, .open>.dropdown-toggle.btn-primary:focus, .open>.dropdown-toggle.btn-primary:hover { background-color: #7460ee; border: 1px solid #7460ee } .btn-success.active.focus, .btn-success.active:focus, .btn-success.active:hover, .btn-success.focus, .btn-success.focus:active, .btn-success:active:focus, .btn-success:active:hover, .btn-success:focus, .open>.dropdown-toggle.btn-success.focus, .open>.dropdown-toggle.btn-success:focus, .open>.dropdown-toggle.btn-success:hover { background-color: #7ace4c; border: 1px solid #7ace4c } .btn-info.active.focus, .btn-info.active:focus, .btn-info.active:hover, .btn-info.focus, .btn-info.focus:active, .btn-info:active:focus, .btn-info:active:hover, .btn-info:focus, .open>.dropdown-toggle.btn-info.focus, .open>.dropdown-toggle.btn-info:focus, .open>.dropdown-toggle.btn-info:hover { background-color: #41b3f9; border: 1px solid #41b3f9 } .btn-warning.active.focus, .btn-warning.active:focus, .btn-warning.active:hover, .btn-warning.focus, .btn-warning.focus:active, .btn-warning:active:focus, .btn-warning:active:hover, .btn-warning:focus, .open>.dropdown-toggle.btn-warning.focus, .open>.dropdown-toggle.btn-warning:focus, .open>.dropdown-toggle.btn-warning:hover { background-color: #fb4; border: 1px solid #fb4 } .btn-danger.active.focus, .btn-danger.active:focus, .btn-danger.active:hover, .btn-danger.focus, .btn-danger.focus:active, .btn-danger:active:focus, .btn-danger:active:hover, .btn-danger:focus, .open>.dropdown-toggle.btn-danger.focus, .open>.dropdown-toggle.btn-danger:focus, .open>.dropdown-toggle.btn-danger:hover { background-color: #f33155; border: 1px solid #f33155 } .btn-inverse, .btn-inverse.active, .btn-inverse.focus, .btn-inverse:active, .btn-inverse:focus, .btn-inverse:hover, .open>.dropdown-toggle.btn-inverse { background-color: #4c5667; border: 1px solid #4c5667; color: #fff } .chat { margin: 0; padding: 0; list-style: none } .chat li { margin-bottom: 10px; padding-bottom: 5px; border-bottom: 1px dotted rgba(120, 130, 140, .13) } .chat li.left .chat-body { margin-left: 60px } .chat li.right .chat-body { margin-right: 60px } .chat li .chat-body p { margin: 0 } .chat .glyphicon, .panel .slidedown .glyphicon { margin-right: 5px } .chat-panel .panel-body { height: 350px; overflow-y: scroll } .login-panel { margin-top: 25% } .flot-chart { display: block; height: 400px } .flot-chart-content { width: 100%; height: 100% } table.dataTable thead .sorting, table.dataTable thead .sorting_asc, table.dataTable thead .sorting_asc_disabled, table.dataTable thead .sorting_desc, table.dataTable thead .sorting_desc_disabled { background: 0 0 } table.dataTable thead .sorting_asc:after { content: "\f0de"; float: right; font-family: fontawesome } table.dataTable thead .sorting_desc:after { content: "\f0dd"; float: right; font-family: fontawesome } table.dataTable thead .sorting:after { content: "\f0dc"; float: right; font-family: fontawesome; color: rgba(50, 50, 50, .5) } .btn-circle { width: 30px; height: 30px; padding: 6px 0; border-radius: 15px; text-align: center; font-size: 12px; line-height: 1.428571429 } .btn-circle.btn-lg { width: 50px; height: 50px; padding: 10px 16px; border-radius: 25px; font-size: 18px; line-height: 1.33 } .btn-circle.btn-xl { width: 70px; height: 70px; padding: 10px 16px; border-radius: 35px; font-size: 24px; line-height: 1.33 } .show-grid [class^=col-] { padding-top: 10px; padding-bottom: 10px; border: 1px solid rgba(120, 130, 140, .13); background-color: #f7fafc } .show-grid { margin: 15px 0 } .huge { font-size: 40px } .white-box { background: #fff; padding: 25px; margin-bottom: 30px } .white-box .box-title { margin: 0 0 12px; font-weight: 500; text-transform: uppercase; font-size: 16px } .panel { border-radius: 0; margin-bottom: 30px; border: 0; box-shadow: none } .panel .panel-heading { border-radius: 0; font-weight: 500; font-size: 16px; padding: 20px 25px } .panel .panel-heading .panel-title { font-size: 16px; color: #263238 } .panel .panel-heading a i { font-size: 12px; margin-left: 8px } .panel .panel-action { float: right } .panel .panel-action a { opacity: .5 } .panel .panel-action a:hover { opacity: 1 } .panel .panel-body { padding: 25px } .panel .panel-body:first-child h3 { margin-top: 0; font-weight: 500; font-family: Rubik, sans-serif; font-size: 14px; text-transform: uppercase } .panel .panel-footer { background: #fff; border-radius: 0; padding: 20px 25px } .panel-green, .panel-success { border-color: #7ace4c } .panel-green .panel-heading, .panel-success .panel-heading { border-color: #7ace4c; color: #fff; background-color: #7ace4c } .panel-green .panel-heading a, .panel-success .panel-heading a { color: #fff } .panel-green .panel-heading a:hover, .panel-success .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-green a, .panel-success a { color: #7ace4c } .panel-green a:hover, .panel-success a:hover { color: #56a12c } .panel-black, .panel-inverse { border-color: #4c5667 } .panel-black .panel-heading, .panel-inverse .panel-heading { border-color: #4c5667; color: #fff; background-color: #4c5667 } .panel-black .panel-heading a, .panel-inverse .panel-heading a { color: #fff } .panel-black .panel-heading a:hover, .panel-inverse .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-black a, .panel-inverse a { color: #4c5667 } .panel-black a:hover, .panel-inverse a:hover { color: #2c313b } .panel-darkblue, .panel-primary { border-color: #7460ee } .panel-darkblue .panel-heading, .panel-primary .panel-heading { border-color: #7460ee; color: #fff; background-color: #7460ee } .panel-darkblue .panel-heading a, .panel-primary .panel-heading a { color: #fff } .panel-darkblue .panel-heading a:hover, .panel-primary .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-darkblue a, .panel-primary a { color: #7460ee } .panel-darkblue a:hover, .panel-primary a:hover { color: #381be7 } .panel-blue, .panel-info { border-color: #41b3f9 } .panel-blue .panel-heading, .panel-info .panel-heading { border-color: #41b3f9; color: #fff; background-color: #41b3f9 } .panel-blue .panel-heading a, .panel-info .panel-heading a { color: #fff } .panel-blue .panel-heading a:hover, .panel-info .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-blue a, .panel-info a { color: #41b3f9 } .panel-blue a:hover, .panel-info a:hover { color: #0791e6 } .panel-danger, .panel-red { border-color: #f33155 } .panel-danger .panel-heading, .panel-red .panel-heading { border-color: #f33155; color: #fff; background-color: #f33155 } .panel-danger .panel-heading a, .panel-red .panel-heading a { color: #fff } .panel-danger .panel-heading a:hover, .panel-red .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-danger a, .panel-red a { color: #f33155 } .panel-danger a:hover, .panel-red a:hover { color: #cc0c2f } .panel-warning, .panel-yellow { border-color: #fb4 } .panel-warning .panel-heading, .panel-yellow .panel-heading { border-color: #fb4; color: #fff; background-color: #fb4 } .panel-warning .panel-heading a, .panel-yellow .panel-heading a { color: #fff } .panel-warning .panel-heading a:hover, .panel-yellow .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-warning a, .panel-yellow a { color: #fb4 } .panel-warning a:hover, .panel-yellow a:hover { color: #f69d00 } .panel-theme, .panel-themecolor { border-color: #2cabe3 } .panel-theme .panel-heading, .panel-themecolor .panel-heading { border-color: #2cabe3; color: #fff; background-color: #2cabe3 } .panel-theme .panel-heading a, .panel-themecolor .panel-heading a { color: #fff } .panel-theme .panel-heading a:hover, .panel-themecolor .panel-heading a:hover { color: rgba(255, 255, 255, .5) } .panel-theme a, .panel-themecolor a { color: #2cabe3 } .panel-theme a:hover, .panel-themecolor a:hover { color: #177eac } .panel-default, .panel-white { border-color: rgba(120, 130, 140, .13) } .panel-default .panel-heading, .panel-white .panel-heading { color: #263238; background-color: #fff; border-bottom: 1px solid rgba(120, 130, 140, .13) } .panel-default .panel-body, .panel-white .panel-body { color: #263238 } .panel-default .panel-action a, .panel-white .panel-action a { color: #263238; opacity: .5 } .panel-default .panel-action a:hover, .panel-white .panel-action a:hover { opacity: 1; color: #263238 } .panel-default .panel-footer, .panel-white .panel-footer { background: #fff; color: #263238; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-info { border-color: #41b3f9 } .full-panel-info .panel-heading { border-color: #41b3f9; color: #fff; background-color: #41b3f9; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-info .panel-body { background: #41b3f9; color: #fff } .full-panel-info .panel-footer { background: #41b3f9; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-info a { color: #41b3f9 } .full-panel-info a:hover { color: #0791e6 } .full-panel-warning { border-color: #fb4 } .full-panel-warning .panel-heading { border-color: #fb4; color: #fff; background-color: #fb4; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-warning .panel-body { background: #fb4; color: #fff } .full-panel-warning .panel-footer { background: #fb4; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-warning a { color: #fb4 } .full-panel-warning a:hover { color: #f69d00 } .full-panel-success { border-color: #7ace4c } .full-panel-success .panel-heading { border-color: #7ace4c; color: #fff; background-color: #7ace4c; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-success .panel-body { background: #7ace4c; color: #fff } .full-panel-success .panel-footer { background: #7ace4c; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-success a { color: #7ace4c } .full-panel-success a:hover { color: #56a12c } .full-panel-purple { border-color: #707cd2 } .full-panel-purple .panel-heading { color: #fff; background-color: #707cd2; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-purple .panel-body { background: #707cd2; color: #fff } .full-panel-purple .panel-footer { background: #707cd2; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-purple a { color: #707cd2 } .full-panel-purple a:hover { color: #3b4abb } .full-panel-danger { border-color: #f33155 } .full-panel-danger .panel-heading { border-color: #f33155; color: #fff; background-color: #f33155; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-danger .panel-body { background: #f33155; color: #fff } .full-panel-danger .panel-footer { background: #f33155; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-danger a { color: #f33155 } .full-panel-danger a:hover { color: #cc0c2f } .full-panel-inverse { border-color: #4c5667 } .full-panel-inverse .panel-heading { border-color: #4c5667; color: #fff; background-color: #4c5667; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-inverse .panel-body { background: #4c5667; color: #fff } .full-panel-inverse .panel-footer { background: #4c5667; color: #fff; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-inverse a { color: #4c5667 } .full-panel-inverse a:hover { color: #2c313b } .full-panel-default { border-color: rgba(120, 130, 140, .13) } .full-panel-default .panel-heading { color: #263238; background-color: #fff; border-bottom: 1px solid rgba(120, 130, 140, .13) } .full-panel-default .panel-body { color: #263238 } .full-panel-default .panel-footer { background: #fff; color: #263238; border-top: 1px solid rgba(120, 130, 140, .13) } .full-panel-default a { color: #263238 } .full-panel-default a:hover { color: #2c313b } .panel-opcl { float: right } .panel-opcl i { margin-left: 8px; font-size: 10px; cursor: pointer } .fa-fw { width: 20px!important; display: inline-block!important; text-align: left!important } .waves-effect { position: relative; cursor: pointer; display: inline-block; overflow: hidden; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent } .waves-effect .waves-ripple { position: absolute; border-radius: 50%; width: 20px; height: 20px; margin-top: -10px; margin-left: -10px; opacity: 0; background: rgba(0, 0, 0, .08); -webkit-transition: all .5s ease-out; -moz-transition: all .5s ease-out; -o-transition: all .5s ease-out; transition: all .5s ease-out; -webkit-transition-property: -webkit-transform, opacity; -moz-transition-property: -moz-transform, opacity; -o-transition-property: -o-transform, opacity; transition-property: transform, opacity; -webkit-transform: scale(0); -moz-transform: scale(0); -ms-transform: scale(0); -o-transform: scale(0); transform: scale(0); pointer-events: none } .waves-effect.waves-light .waves-ripple { background: rgba(255, 255, 255, .4); background: -webkit-radial-gradient(rgba(255, 255, 255, .2) 0, rgba(255, 255, 255, .3) 40%, rgba(255, 255, 255, .4) 50%, rgba(255, 255, 255, .5) 60%, rgba(255, 255, 255, 0) 70%); background: -o-radial-gradient(rgba(255, 255, 255, .2) 0, rgba(255, 255, 255, .3) 40%, rgba(255, 255, 255, .4) 50%, rgba(255, 255, 255, .5) 60%, rgba(255, 255, 255, 0) 70%); background: -moz-radial-gradient(rgba(255, 255, 255, .2) 0, rgba(255, 255, 255, .3) 40%, rgba(255, 255, 255, .4) 50%, rgba(255, 255, 255, .5) 60%, rgba(255, 255, 255, 0) 70%); background: radial-gradient(rgba(255, 255, 255, .2) 0, rgba(255, 255, 255, .3) 40%, rgba(255, 255, 255, .4) 50%, rgba(255, 255, 255, .5) 60%, rgba(255, 255, 255, 0) 70%) } .waves-effect.waves-classic .waves-ripple { background: rgba(0, 0, 0, .2) } .waves-effect.waves-classic.waves-light .waves-ripple { background: rgba(255, 255, 255, .4) } .waves-notransition { -webkit-transition: none!important; -moz-transition: none!important; -o-transition: none!important; transition: none!important } .waves-button, .waves-circle { -webkit-transform: translateZ(0); -moz-transform: translateZ(0); -ms-transform: translateZ(0); -o-transform: translateZ(0); transform: translateZ(0); -webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%) } .waves-button, .waves-button-input, .waves-button:hover, .waves-button:visited { white-space: nowrap; vertical-align: middle; cursor: pointer; border: none; outline: 0; color: inherit; background-color: rgba(0, 0, 0, 0); font-size: 1em; line-height: 1em; text-align: center; text-decoration: none; z-index: 1 } .waves-button { padding: .85em 1.1em; border-radius: .2em } .waves-button-input { margin: 0; padding: .85em 1.1em } .waves-input-wrapper { border-radius: .2em; vertical-align: bottom } .waves-input-wrapper.waves-button { padding: 0 } .waves-input-wrapper .waves-button-input { position: relative; top: 0; left: 0; z-index: 1 } .waves-circle { text-align: center; width: 2.5em; height: 2.5em; line-height: 2.5em; border-radius: 50% } .waves-float { -webkit-mask-image: none; -webkit-box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, .12); box-shadow: 0 1px 1.5px 1px rgba(0, 0, 0, .12); -webkit-transition: all 300ms; -moz-transition: all 300ms; -o-transition: all 300ms; transition: all 300ms } .waves-float:active { -webkit-box-shadow: 0 8px 20px 1px rgba(0, 0, 0, .3); box-shadow: 0 8px 20px 1px rgba(0, 0, 0, .3) } .waves-block { display: block } .common-list { margin: 0; padding: 0 } .common-list li { list-style: none; display: block } .common-list li a { padding: 12px 0; color: #313131; display: block } .common-list li a:hover { color: #2cabe3 } .checkbox { padding-left: 20px } .checkbox label { display: inline-block; padding-left: 5px; position: relative } .checkbox label::before { -o-transition: .3s ease-in-out; -webkit-transition: .3s ease-in-out; background-color: #fff; border-radius: 1px; border: 1px solid rgba(120, 130, 140, .13); content: ""; display: inline-block; height: 17px; left: 0; margin-left: -20px; position: absolute; transition: .3s ease-in-out; width: 17px; outline: 0!important } .checkbox label::after { color: #263238; display: inline-block; font-size: 11px; height: 16px; left: 0; margin-left: -20px; padding-left: 3px; padding-top: 1px; position: absolute; top: 0; width: 16px } .checkbox input[type=checkbox] { cursor: pointer; opacity: 0; z-index: 1; outline: 0!important } .checkbox input[type=checkbox]:disabled+label { opacity: .65 } .checkbox input[type=checkbox]:focus+label::before { outline-offset: -2px; outline: 0; outline: dotted thin } .checkbox input[type=checkbox]:checked+label::after { content: "\f00c"; font-family: FontAwesome } .checkbox input[type=checkbox]:disabled+label::before { background-color: #e4e7ea; cursor: not-allowed } .checkbox.checkbox-circle label::before { border-radius: 50% } .checkbox.checkbox-inline { margin-top: 0 } .checkbox.checkbox-single label { height: 17px } .checkbox-primary input[type=checkbox]:checked+label::before { background-color: #7460ee; border-color: #7460ee } .checkbox-primary input[type=checkbox]:checked+label::after { color: #fff } .checkbox-danger input[type=checkbox]:checked+label::before { background-color: #f33155; border-color: #f33155 } .checkbox-danger input[type=checkbox]:checked+label::after { color: #fff } .checkbox-info input[type=checkbox]:checked+label::before { background-color: #41b3f9; border-color: #41b3f9 } .checkbox-info input[type=checkbox]:checked+label::after { color: #fff } .checkbox-warning input[type=checkbox]:checked+label::before { background-color: #fb4; border-color: #fb4 } .checkbox-warning input[type=checkbox]:checked+label::after { color: #fff } .checkbox-success input[type=checkbox]:checked+label::before { background-color: #7ace4c; border-color: #7ace4c } .checkbox-success input[type=checkbox]:checked+label::after { color: #fff } .checkbox-purple input[type=checkbox]:checked+label::before { background-color: #707cd2; border-color: #707cd2 } .checkbox-purple input[type=checkbox]:checked+label::after { color: #fff } .checkbox-red input[type=checkbox]:checked+label::before { background-color: #f33155; border-color: #f33155 } .checkbox-red input[type=checkbox]:checked+label::after { color: #fff } .checkbox-inverse input[type=checkbox]:checked+label::before { background-color: #4c5667; border-color: #4c5667 } .checkbox-inverse input[type=checkbox]:checked+label::after { color: #fff } .radio { padding-left: 20px } .radio label { display: inline-block; padding-left: 5px; position: relative } .radio label::before { -o-transition: border .5s ease-in-out; -webkit-transition: border .5s ease-in-out; background-color: #fff; border-radius: 50%; border: 1px solid rgba(120, 130, 140, .13); content: ""; display: inline-block; height: 17px; left: 0; margin-left: -20px; position: absolute; transition: border .5s ease-in-out; width: 17px; outline: 0!important } .radio label::after { -moz-transition: -moz-transform .3s cubic-bezier(.8, -.33, .2, 1.33); -ms-transform: scale(0, 0); -o-transform: scale(0, 0); -o-transition: -o-transform .3s cubic-bezier(.8, -.33, .2, 1.33); -webkit-transform: scale(0, 0); -webkit-transition: -webkit-transform .3s cubic-bezier(.8, -.33, .2, 1.33); background-color: #263238; border-radius: 50%; content: " "; display: inline-block; height: 7px; left: 5px; margin-left: -20px; position: absolute; top: 5px; transform: scale(0, 0); transition: transform .3s cubic-bezier(.8, -.33, .2, 1.33); width: 7px } .radio input[type=radio] { cursor: pointer; opacity: 0; z-index: 1; outline: 0!important } .radio input[type=radio]:disabled+label { opacity: .65 } .radio input[type=radio]:focus+label::before { outline-offset: -2px; outline: -webkit-focus-ring-color auto 5px; outline: dotted thin } .radio input[type=radio]:checked+label::after { -ms-transform: scale(1, 1); -o-transform: scale(1, 1); -webkit-transform: scale(1, 1); transform: scale(1, 1) } .radio input[type=radio]:disabled+label::before { cursor: not-allowed } .radio.radio-inline { margin-top: 0 } .radio.radio-single label { height: 17px } .radio-primary input[type=radio]+label::after { background-color: #7460ee } .radio-primary input[type=radio]:checked+label::before { border-color: #7460ee } .radio-primary input[type=radio]:checked+label::after { background-color: #7460ee } .radio-danger input[type=radio]+label::after { background-color: #f33155 } .radio-danger input[type=radio]:checked+label::before { border-color: #f33155 } .radio-danger input[type=radio]:checked+label::after { background-color: #f33155 } .radio-info input[type=radio]+label::after { background-color: #41b3f9 } .radio-info input[type=radio]:checked+label::before { border-color: #41b3f9 } .radio-info input[type=radio]:checked+label::after { background-color: #41b3f9 } .radio-warning input[type=radio]+label::after { background-color: #fb4 } .radio-warning input[type=radio]:checked+label::before { border-color: #fb4 } .radio-warning input[type=radio]:checked+label::after { background-color: #fb4 } .radio-success input[type=radio]+label::after { background-color: #7ace4c } .radio-success input[type=radio]:checked+label::before { border-color: #7ace4c } .radio-success input[type=radio]:checked+label::after { background-color: #7ace4c } .radio-purple input[type=radio]+label::after { background-color: #707cd2 } .radio-purple input[type=radio]:checked+label::before { border-color: #707cd2 } .radio-purple input[type=radio]:checked+label::after { background-color: #707cd2 } .radio-red input[type=radio]+label::after { background-color: #f33155 } .radio-red input[type=radio]:checked+label::before { border-color: #f33155 } .radio-red input[type=radio]:checked+label::after { background-color: #f33155 } .fileupload { overflow: hidden; position: relative } .fileupload input.upload { cursor: pointer; filter: alpha(opacity=0); font-size: 20px; margin: 0; opacity: 0; padding: 0; position: absolute; right: 0; top: 0 } .model_img { cursor: pointer } .myadmin-dd .dd-list .dd-item .dd-handle { background: #fff; border: 1px solid rgba(120, 130, 140, .13); padding: 8px 16px; height: auto; font-weight: 600; border-radius: 0 } .myadmin-dd .dd-list .dd-item .dd-handle:hover { color: #41b3f9 } .myadmin-dd .dd-list .dd-item button { height: auto; font-size: 17px; margin: 8px auto; color: #263238; width: 30px } .myadmin-dd-empty .dd-list .dd3-handle { border: 1px solid rgba(120, 130, 140, .13); border-bottom: 0; background: #fff; height: 36px; width: 36px } .myadmin-dd-empty .dd-list .dd3-handle:before { color: inherit; top: 7px } .myadmin-dd-empty .dd-list .dd3-handle:hover { color: #41b3f9 } .myadmin-dd-empty .dd-list .dd3-content { height: auto; border: 1px solid rgba(120, 130, 140, .13); padding: 8px 16px 8px 46px; background: #fff; font-weight: 600 } .myadmin-dd-empty .dd-list .dd3-content:hover { color: #41b3f9 } .myadmin-dd-empty .dd-list button { width: 26px; height: 26px; font-size: 16px; font-weight: 600 } .settings_box { position: absolute; top: 75px; right: 0; z-index: 100 } .settings_box a { background: #fff; padding: 15px; display: inline-block; vertical-align: top } .settings_box a i { display: block; -webkit-animation-name: rotate; -webkit-animation-duration: 2s; -moz-animation-name: rotate; -moz-animation-duration: 2s; -moz-animation-iteration-count: infinite; -moz-animation-timing-function: linear; animation-name: rotate; font-size: 16px; animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: linear } @-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg) } to { -webkit-transform: rotate(360deg) } } @-moz-keyframes rotate { from { -moz-transform: rotate(0deg) } to { -moz-transform: rotate(360deg) } } @keyframes rotate { from { transform: rotate(0deg) } to { transform: rotate(360deg) } } .theme_color { margin: 0; padding: 0; display: inline-block; overflow: hidden; width: 0; transition: .5s ease-out; background: #fff } .theme_color li { list-style: none; width: 30%; float: left; margin: 0 1.5% } .theme_color li a { padding: 5px; height: 50px; display: block } .theme_color li a.theme-green { background: #7ace4c } .theme_color li a.theme-red { background: #f33155 } .theme_color li a.theme-dark { background: #4c5667 } .theme_block { width: 200px; padding: 30px } ul.common li { display: inline-block; line-height: 40px; list-style: none none; width: 48% } ul.common li a { color: #313131 } ul.common li a:hover { color: #41b3f9 } .circle { border-radius: 100%; text-align: center; color: #fff } .circle-sm { width: 40px; padding-top: 12px; height: 40px; font-size: 14px!important } .circle-md { width: 60px; padding-top: 15px; height: 60px; font-size: 24px!important } .circle-lg { width: 80px; padding-top: 20px; height: 80px; font-size: 30px!important } .row-in i { font-size: 24px } .megamenu { left: 0; right: 0; width: 100% } .mega-dropdown { position: static!important } .mega-dropdown-menu { padding: 20px 20px 20px 80px; width: 100%; -webkit-box-shadow: none; border: 0; box-shadow: 0 2px 10px rgba(0, 0, 0, .1)!important } .mega-dropdown-menu>li>ul { padding: 0; margin: 0 } .mega-dropdown-menu>li>ul>li { list-style: none } .mega-dropdown-menu>li>ul>li>a { display: block; padding: 8px 0; clear: both; line-height: 1.428571429; color: #313131; white-space: normal } .mega-dropdown-menu>li>ul>li>a:focus, .mega-dropdown-menu>li>ul>li>a:hover { text-decoration: none; color: #2cabe3 } .mega-dropdown-menu .dropdown-header { font-size: 16px; font-weight: 500; padding: 8px 0; margin-top: 12px } .mega-dropdown-menu li.demo-box a { color: #fff; display: block } .mega-dropdown-menu li.demo-box a:hover { opacity: .8 } .mailbox { width: 280px; overflow: auto; padding-bottom: 0 } .message-center a { border-bottom: 1px solid rgba(120, 130, 140, .13); display: block; padding: 9px 15px } .message-center a:hover { background: #f7fafc } .message-center .user-img { width: 40px; float: left; position: relative; margin: 0 10px 15px 0 } .message-center .user-img img { width: 100% } .message-center .user-img .profile-status { border: 2px solid #fff; border-radius: 50%; display: inline-block; height: 10px; left: 30px; position: absolute; top: 1px; width: 10px } .message-center .user-img .online { background: #7ace4c } .message-center .user-img .busy { background: #f33155 } .message-center .user-img .away, .message-center .user-img .offline { background: #fb4 } .message-center .mail-contnet h5 { margin: 0; font-weight: 400; text-overflow: ellipsis; overflow: hidden; white-space: nowrap } .message-center .mail-contnet .mail-desc { font-size: 12px; display: block; margin: 5px 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color: #263238 } .message-center .mail-contnet .time { display: block; font-size: 10px; color: #263238 } .mail-contnet a.action { margin-left: 10px; font-size: 12px; visibility: hidden } .mail-contnet:hover a.action { visibility: visible } .inbox-center td { white-space: nowrap } .inbox-center .unread td { font-weight: 400 } .inbox-center a { color: #313131; padding: 2px 0 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block } .comment-center { margin: 0 -25px } .comment-center .comment-body { border-bottom: 1px solid rgba(120, 130, 140, .13); display: table; width: 100%; padding: 20px 25px } .comment-center .comment-body:hover { background: #f7fafc } .comment-center .user-img { width: 40px; display: table-cell; position: relative; margin: 0 10px 0 0 } .comment-center .user-img img { width: 100% } .comment-center .mail-contnet { display: table-cell; padding-left: 15px; vertical-align: top } .comment-center .mail-contnet h5 { margin-top: 0; font-weight: 400; text-overflow: ellipsis; overflow: hidden; white-space: nowrap } .comment-center .mail-contnet .mail-desc { font-size: 14px; display: block; margin: 15px 0; line-height: 25px; color: #848a96; overflow: hidden; max-height: 52px; text-overflow: ellipsis } .comment-center .mail-contnet .time { display: inline-block; font-size: 12px; color: #98a6ad } .sales-report { background: #f7fafc; margin: 12px -25px; padding: 15px } .dropdown-alerts, .dropdown-tasks { padding: 0 } .dropdown-alerts li a, .dropdown-tasks li a, .mailbox li>a { padding: 15px 20px } .dropdown-alerts li.divider, .dropdown-tasks li.divider { margin: 0 } .row-in-br { border-right: 1px solid rgba(120, 130, 140, .13) } .col-in { list-style: none; padding: 0; margin: 0 } .col-in li { display: inline-block; vertical-align: middle; padding: 0 10px } .col-in li .circle { display: inline-block } .col-in li.col-middle { width: 40% } .col-in li.col-last { float: right } .col-in h3 { font-size: 36px; font-weight: 100 } .basic-list { padding: 0 } .basic-list li { display: block; padding: 15px 0; border-bottom: 1px solid rgba(120, 130, 140, .13); line-height: 27px } .basic-list li:last-child { border-bottom: 0 } .steamline { position: relative; border-left: 1px solid rgba(120, 130, 140, .13); margin-left: 20px } .steamline .sl-left { float: left; margin-left: -20px; z-index: 1; width: 40px; line-height: 40px; text-align: center; height: 40px; border-radius: 100%; color: #fff; background: #263238; margin-right: 15px } .steamline .sl-left img { max-width: 40px } .steamline .sl-right { padding-left: 50px } .steamline .sl-right .desc, .steamline .sl-right .inline-photos { margin-bottom: 30px } .steamline .sl-right div>a { color: #263238; font-weight: 400 } .steamline .sl-item { border-bottom: 1px solid rgba(120, 130, 140, .13); margin: 20px 0 } .sl-date { font-size: 10px; color: #98a6ad } .time-item { /*border-color: $border;*/ padding-bottom: 1px; position: relative } .time-item:before { content: " "; display: table } .time-item:after { background-color: #fff; border-color: rgba(120, 130, 140, .13); border-radius: 10px; border-style: solid; border-width: 2px; bottom: 0; content: ''; height: 14px; left: 0; margin-left: -8px; position: absolute; top: 5px; width: 14px } .time-item-item:after { content: " "; display: table } .item-info { margin-bottom: 15px; margin-left: 15px } .item-info p { margin-bottom: 10px!important } .user-bg { margin: -25px; height: 230px; overflow: hidden; position: relative } .user-bg .overlay-box { background: #707cd2; opacity: .9; position: absolute; top: 0; left: 0; right: 0; height: 100%; text-align: center } .user-bg .overlay-box .user-content { padding: 15px; margin-top: 30px } .user-btm-box { padding: 40px 0 10px; clear: both; overflow: hidden } .vertical .carousel-inner { height: 100%; position: relative } .carousel.vertical .item { -webkit-transition: .6s ease-in-out top; -moz-transition: .6s ease-in-out top; -ms-transition: .6s ease-in-out top; -o-transition: .6s ease-in-out top; transition: .6s ease-in-out top } .carousel.vertical .active { top: 0 } .carousel.vertical .next { top: 400px } .carousel.vertical .prev { top: -400px } .carousel.vertical .next.left, .carousel.vertical .prev.right { top: 0 } .carousel.vertical .active.left { top: -400px } .carousel.vertical .active.right { top: 400px } .carousel.vertical .item { left: 0 } .twi-user img { margin-right: 20px; width: 50px } .twi-user { margin: 18px 0 } .carousel-inner h3 { overflow: hidden } .carousel-inner>.item>img { width: 100% } .chart-box { margin: 25px -15px -17px -17px } .chat-list { list-style: none; padding: 0 20px } .chat-list li { margin-bottom: 24px; overflow: auto } .chat-list .chat-image { display: inline-block; float: left; text-align: center; width: 50px } .chat-list .chat-image img { border-radius: 100%; width: 100% } .chat-list .chat-text { background: #e5f7ff; border-radius: 0 8px 8px; display: inline-block; padding: 15px; font-size: 14px; position: relative } .chat-list .chat-text h4 { color: #1a2942; display: block; font-size: 14px; font-style: normal; font-weight: 500; margin: 0; line-height: 15px; position: relative } .chat-list .chat-text p { margin: 0; padding-top: 3px } .chat-list .chat-text b { font-size: 10px; opacity: .8 } .chat-list .chat-body { display: inline-block; float: left; font-size: 12px; margin-left: 12px; width: 65% } .chat-list .odd .chat-image { float: right!important } .chat-list .odd .chat-body { float: right!important; margin-right: 12px; text-align: right } .chat-list .odd .chat-text { background: #f7f7f7; border-radius: 8px 0 8px 8px } .chat-send { padding-left: 0; padding-right: 30px } .chat-send button { width: 100% } .weather-box .weather-top { overflow: hidden; padding: 10px 25px; margin: 0 -25px; background: #f7fafc } .weather-box .weather-top h2 { line-height: 24px } .weather-box .weather-top h2 small { font-size: 13px } .weather-box .weather-top .today_crnt { font-size: 45px; font-weight: 100 } .weather-box .weather-top .today_crnt canvas { display: inline-block; margin-right: 10px; vertical-align: middle } .weather-box .weather-info { padding: 10px 0 } .weather-box .weather-time { overflow: hidden; text-align: center; padding-top: 15px } .weather-box .weather-time li span { display: block } .weather-box .weather-time li canvas { font-size: 20px; margin: 10px 0 } .demo-container { width: 100%; height: 350px } .demo-placeholder { width: 100%; height: 100%; font-size: 14px; line-height: 1.2em } .myadmin-alert { border-radius: 0; color: #fff; padding: 12px 30px 12px 12px; position: relative; text-align: left } .myadmin-alert a { color: inherit; font-weight: 600; text-decoration: underline } .myadmin-alert h4 { color: inherit; font-size: 14px; font-weight: 600; line-height: normal; margin: 0 } .myadmin-alert .img { border-radius: 3px; height: 40px; left: 12px; position: absolute; top: 12px; width: 40px } .myadmin-alert-img { min-height: 64px; padding-left: 65px } .myadmin-alert-icon { padding-left: 20px } .myadmin-alert-icon i { padding-right: 10px } .myadmin-alert .closed { color: rgba(255, 255, 255, .5); font-size: 20px; font-weight: 500; padding: 4px; position: absolute; right: 3px; text-decoration: none; top: 0 } .myadmin-alert .closed:hover { color: #fff } .myadmin-alert-click { cursor: pointer; padding-right: 12px } .myadmin-alert .primary { background: rgba(0, 0, 0, .4); border: none; border-radius: 3px; color: inherit; outline: 0; padding: 4px 10px } .myadmin-alert .cancel { background: rgba(255, 255, 255, .4); border: none; border-radius: 3px; color: rgba(0, 0, 0, .8); outline: 0; padding: 4px 10px } .myadmin-alert .cancel:hover, .myadmin-alert .primary:hover { opacity: .9 } .myadmin-alert-bottom, .myadmin-alert-bottom-left, .myadmin-alert-bottom-right, .myadmin-alert-fullscreen, .myadmin-alert-top, .myadmin-alert-top-left, .myadmin-alert-top-right { box-shadow: 2px 2px 2px rgba(0, 0, 0, .1); display: none; position: fixed; z-index: 1000 } .myadmin-alert-top { left: 0; right: 0; top: 0 } .myadmin-alert-bottom { bottom: 0; left: 0; right: 0 } .myadmin-alert-top-left { left: 20px; top: 80px } .myadmin-alert-top-right { right: 20px; top: 80px } .myadmin-alert-bottom-left { bottom: 20px; left: 20px } .myadmin-alert-bottom-right { bottom: 20px; right: 20px } .myadmin-alert-fullsize { left: 50%; margin: -20px; top: 50% } .alert-custom { background: #2cabe3; color: #fff; border-color: #2cabe3 } .alert-inverse { background: #4c5667; color: #fff; border-color: #4c5667 } .alert-success { background: #7ace4c; color: #fff; border-color: #7ace4c } .alert-dark { background: #313131; color: #fff; border-color: #313131 } .alert-warning { background: #fb4; color: #fff; border-color: #fb4 } .alert-danger { background: #f33155; color: #fff; border-color: #f33155 } .alert-primary { background: #707cd2; color: #fff; border-color: #707cd2 } .alert-info { background: #41b3f9; color: #fff; border-color: #41b3f9 } .alert-info .closed, .alert-info a.closed:hover { color: inherit } .tab-content { margin-top: 30px } .customtab { border-bottom: 2px solid #f7fafc } .customtab li.active a, .customtab li.active a:focus, .customtab li.active a:hover { background: #fff; border: 0; border-bottom: 2px solid #2cabe3; margin-bottom: -1px; color: #2cabe3 } .customtab li a, .customtab li a:focus, .customtab li a:hover { border: 0 } .customtab2 { border-bottom: 1px solid #f7fafc; border-top: 1px solid #f7fafc; padding: 10px 0 } .customtab2 li.active a, .customtab2 li.active a:focus, .customtab2 li.active a:hover { background: #2cabe3; border: 1px solid #2cabe3; color: #fff } .customtab2 li a, .customtab2 li a:focus, .customtab2 li a:hover { border: 0 } .vtabs { display: table } .vtabs .tabs-vertical { width: 150px; border-right: 1px solid rgba(120, 130, 140, .13); display: table-cell; vertical-align: top } .vtabs .tabs-vertical li a { color: #263238; margin-bottom: 10px } .vtabs .tab-content { display: table-cell; padding: 20px; vertical-align: top } .tabs-vertical li.active a, .tabs-vertical li.active a:focus, .tabs-vertical li.active a:hover { background: #2cabe3; border: 0; border-right: 2px solid #2cabe3; margin-right: -1px; color: #fff } .customvtab .tabs-vertical li.active a, .customvtab .tabs-vertical li.active a:focus, .customvtab .tabs-vertical li.active a:hover { background: #fff; border: 0; border-right: 2px solid #2cabe3; margin-right: -1px; color: #263238 } .nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover { background: #2cabe3; color: #fff } .nav-pills>li>a { color: #263238; border-radius: 0 } .panel-group .panel .panel-heading .accordion-toggle.collapsed:before, .panel-group .panel .panel-heading a[data-toggle=collapse].collapsed:before { content: '\e64b' } .panel-group .panel .panel-heading a[data-toggle=collapse] { display: block } .panel-group .panel .panel-heading a[data-toggle=collapse]:before { content: '\e648'; display: block; float: right; font-family: themify; font-size: 14px; text-align: right; width: 25px } .panel-group .panel .panel-heading .accordion-toggle { display: block } .panel-group .panel .panel-heading .accordion-toggle:before { content: '\e648'; display: block; float: right; font-family: themify; font-size: 14px; text-align: right; width: 25px } .panel-group .panel .panel-heading+.panel-collapse .panel-body { border-top: none } .panel-group .panel-heading { padding: 12px 20px } .progress { -webkit-box-shadow: none!important; background-color: rgba(120, 130, 140, .13); box-shadow: none!important; height: 4px; border-radius: 0; margin-bottom: 18px; overflow: hidden } .progress-bar { box-shadow: none; font-size: 8px; font-weight: 600; line-height: 12px } .progress.progress-sm { height: 8px!important } .progress.progress-sm .progress-bar { font-size: 8px; line-height: 5px } .progress.progress-md { height: 15px!important } .progress.progress-md .progress-bar { font-size: 10.8px; line-height: 14.4px } .progress.progress-lg { height: 20px!important } .progress.progress-lg .progress-bar { font-size: 12px; line-height: 20px } .progress-bar-primary { background-color: #7460ee } .progress-bar-success { background-color: #7ace4c } .progress-bar-info { background-color: #41b3f9 } .progress-bar-megna { background-color: #01c0c8 } .progress-bar-warning { background-color: #fb4 } .progress-bar-danger { background-color: #f33155 } .progress-bar-inverse { background-color: #4c5667 } .progress-bar-purple { background-color: #707cd2 } .progress-bar-custom { background-color: #41b3f9 } .progress-animated { -webkit-animation-duration: 5s; -webkit-animation-name: myanimation; -webkit-transition: 5s all; animation-duration: 5s; animation-name: myanimation; transition: 5s all } @-webkit-keyframes myanimation { from { width: 0 } } @keyframes myanimation { from { width: 0 } } .progress-vertical { min-height: 250px; height: 250px; width: 4px; position: relative; display: inline-block; margin-bottom: 0; margin-right: 20px } .progress-vertical .progress-bar { width: 100% } .progress-vertical-bottom { min-height: 250px; height: 250px; position: relative; width: 4px; display: inline-block; margin-bottom: 0; margin-right: 20px } .progress-vertical-bottom .progress-bar { width: 100%; position: absolute; bottom: 0 } .progress-vertical-bottom.progress-sm, .progress-vertical.progress-sm { width: 8px!important } .progress-vertical-bottom.progress-sm .progress-bar, .progress-vertical.progress-sm .progress-bar { font-size: 8px; line-height: 5px } .progress-vertical-bottom.progress-md, .progress-vertical.progress-md { width: 15px!important } .progress-vertical-bottom.progress-md .progress-bar, .progress-vertical.progress-md .progress-bar { font-size: 10.8px; line-height: 14.4px } .progress-vertical-bottom.progress-lg, .progress-vertical.progress-lg { width: 20px!important } .progress-vertical-bottom.progress-lg .progress-bar, .progress-vertical.progress-lg .progress-bar { font-size: 12px; line-height: 20px } .timeline { position: relative; padding: 20px 0; list-style: none; max-width: 1200px; margin: 0 auto } .timeline:before { content: " "; position: absolute; top: 0; bottom: 0; left: 50%; width: 3px; margin-left: -1.5px; background-color: #eee } .timeline>li { position: relative; margin-bottom: 20px } .timeline>li:after, .timeline>li:before { content: " "; display: table } .timeline>li:after { clear: both } .timeline>li>.timeline-panel { float: left; position: relative; width: 46%; padding: 20px; border: 1px solid rgba(120, 130, 140, .13); border-radius: 0; -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, .05); box-shadow: 0 1px 6px rgba(0, 0, 0, .05) } .timeline>li>.timeline-panel:before { content: " "; display: inline-block; position: absolute; top: 26px; right: -8px; border-top: 8px solid transparent; border-right: 0 solid rgba(120, 130, 140, .13); border-bottom: 8px solid transparent; border-left: 8px solid rgba(120, 130, 140, .13) } .timeline>li>.timeline-panel:after { content: " "; display: inline-block; position: absolute; top: 27px; right: -7px; border-top: 7px solid transparent; border-right: 0 solid #fff; border-bottom: 7px solid transparent; border-left: 7px solid #fff } .timeline>li>.timeline-badge { z-index: 100; position: absolute; top: 16px; left: 50%; width: 50px; height: 50px; margin-left: -25px; border-radius: 50%; text-align: center; font-size: 1.4em; line-height: 50px; color: #fff; overflow: hidden; background-color: #4c5667 } .timeline>li.timeline-inverted>.timeline-panel { float: right } .timeline>li.timeline-inverted>.timeline-panel:before { right: auto; left: -8px; border-right-width: 8px; border-left-width: 0 } .timeline>li.timeline-inverted>.timeline-panel:after { right: auto; left: -7px; border-right-width: 7px; border-left-width: 0 } .timeline-badge.primary { background-color: #7460ee!important } .timeline-badge.success { background-color: #7ace4c!important } .timeline-badge.warning { background-color: #fb4!important } .timeline-badge.danger { background-color: #f33155!important } .timeline-badge.info { background-color: #41b3f9!important } .timeline-title { margin-top: 0; color: inherit; font-weight: 400 } .timeline-body>p, .timeline-body>ul { margin-bottom: 0 } .timeline-body>p+p { margin-top: 5px } .chart { position: relative; display: inline-block; width: 100px; height: 100px; margin-top: 20px; margin-bottom: 20px; text-align: center } .chart canvas { position: absolute; top: 0; left: 0 } .chart.chart-widget-pie { margin-top: 5px; margin-bottom: 5px } .pie-chart>span { left: 0; margin-top: -2px; position: absolute; right: 0; text-align: center; top: 50%; transform: translateY(-50%) } .chart>span>img { left: 0; position: absolute; right: 0; text-align: center; top: 50%; width: 60%; height: 60%; transform: translateY(-50%); margin: 0 auto } .percent { display: inline-block; line-height: 100px; z-index: 2; font-weight: 600; font-size: 18px; color: #263238 } .percent:after { content: '%'; margin-left: .1em; font-size: .8em } .table { margin-bottom: 10px } .table-hover>tbody>tr:hover, .table-striped>tbody>tr:nth-of-type(odd), .table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active { background-color: #f7fafc!important } .table-bordered, .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th { border-top: 1px solid #e4e7ea } .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th { padding: 15px 8px } .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th { border: 1px solid #e4e7ea } .table>thead>tr>th { vertical-align: bottom; border-bottom: 1px solid #e4e7ea } tbody { color: #797979 } th { color: #666; font-weight: 500 } .table-bordered { border: 1px solid #e4e7ea } table.focus-on tbody tr.focused td, table.focus-on tbody tr.focused th { background-color: #2cabe3; color: #fff } .table-rep-plugin .table-responsive { border: none!important } .table-rep-plugin tbody th { font-size: 14px; font-weight: 400 } .jsgrid .jsgrid-table { margin-bottom: 0 } .jsgrid-selected-row>td { background: #f7fafc; border-color: #f7fafc } .jsgrid-header-row>th { background: #fff } .footable-odd { background-color: #f7fafc } .form-control-line { border-left: 0 none; border-radius: 0; border-right: 0 none; border-top: 0 none; box-shadow: none; padding-left: 0 } .has-success .form-control { border-color: #7ace4c; box-shadow: none!important } .has-warning .form-control { border-color: #fb4; box-shadow: none!important } .has-error .form-control { border-color: #f33155; box-shadow: none!important } .input-group-addon { border-radius: 2px; border: 1px solid rgba(120, 130, 140, .13) } .input-daterange input:first-child, .input-daterange input:last-child { border-radius: 0 } .form-material .form-group { overflow: hidden } .form-material .form-control { background-color: rgba(0, 0, 0, 0); background-position: center bottom, center calc(99%); background-repeat: no-repeat; background-size: 0 2px, 100% 1px; padding: 0; transition: background 0s ease-out 0s } .form-material .form-control, .form-material .form-control.focus, .form-material .form-control:focus { background-image: linear-gradient(#707cd2, #707cd2), linear-gradient(rgba(120, 130, 140, .13), rgba(120, 130, 140, .13)); border: 0; border-radius: 0; box-shadow: none; float: none } .form-material .form-control.focus, .form-material .form-control:focus { background-size: 100% 2px, 100% 1px; outline: 0; transition-duration: .3s } .form-bordered .form-group { border-bottom: 1px solid rgba(120, 130, 140, .13); padding-bottom: 20px } .select2-container .select2-choice { background-image: none!important; border: none!important; height: auto!important; padding: 0!important; line-height: 22px!important; background-color: transparent!important; box-shadow: none!important } .select2-container .select2-choice .select2-arrow { background-image: none!important; background: 0 0; border: none; width: 14px; top: -2px } .select2-container .select2-container-multi.form-control { height: auto } .select2-results .select2-highlighted { color: #fff; background-color: #41b3f9 } .select2-drop-active { border: 1px solid #e3e3e3!important; padding-top: 5px } .select2-search input { border: 1px solid rgba(120, 130, 140, .13) } .select2-container-multi { width: 100% } .select2-container-multi .select2-choices { border: 1px solid #border!important; box-shadow: none!important; background-image: none!important; border-radius: 0!important; min-height: 38px } .select2-container-multi .select2-choices .select2-search-choice { padding: 4px 7px 4px 18px; margin: 5px 0 3px 5px; color: #555; background: #f5f5f5; border-color: rgba(120, 130, 140, .13); -webkit-box-shadow: none; box-shadow: none } .select2-container-multi .select2-choices .select2-search-field input { padding: 7px 7px 7px 10px; font-family: inherit } .icon-list-demo div { cursor: pointer; line-height: 60px; white-space: nowrap; color: #313131 } .icon-list-demo div:hover { color: #263238 } .icon-list-demo div p { margin: 10px 0; padding: 5px 0 } .icon-list-demo i { -webkit-transition: all .2s; -webkit-transition: font-size .2s; display: inline-block; font-size: 18px; margin: 0 15px 0 10px; text-align: left; vertical-align: middle; width: auto; transition: all .3s ease 0s } .icon-list-demo .col-md-4 { border-radius: 0 } .icon-list-demo .col-md-4:hover { background-color: #f7fafc } .icon-list-demo .col-md-4:hover i { font-size: 2em } .gmaps, .gmaps-panaroma { height: 300px; background: #e4e7ea; border-radius: 3px } .gmaps-overlay { display: block; text-align: center; color: #fff; font-size: 16px; line-height: 40px; background: #7460ee; border-radius: 4px; padding: 10px 20px } .gmaps-overlay_arrow { left: 50%; margin-left: -16px; width: 0; height: 0; position: absolute } .gmaps-overlay_arrow.above { bottom: -15px; border-left: 16px solid transparent; border-right: 16px solid transparent; border-top: 16px solid #7460ee } .gmaps-overlay_arrow.below { top: -15px; border-left: 16px solid transparent; border-right: 16px solid transparent; border-bottom: 16px solid #7460ee } .jvectormap-zoomin, .jvectormap-zoomout { width: 10px; height: 10px; line-height: 10px } .jvectormap-zoomout { top: 40px } .error-box { height: 100%; position: fixed; top: 20%; width: 100% } .error-box .footer { width: 100%; left: 0; right: 0 } .error-body { padding-top: 5% } .error-body h1 { font-size: 210px; font-weight: 900; line-height: 210px } .login-register { /*background: url(../../plugins/images/login-register.jpg) center center/cover no-repeat!important;*/ height: 100%; position: fixed } .login-box { background: #fff; width: 400px; margin: 10% auto 0 } .login-box .footer { width: 100%; left: 0; right: 0 } .login-box .social { display: block; margin-bottom: 30px } #recoverform { display: none } .new-login-register { position: fixed; height: 100% } .new-login-register .lg-info-panel { /*background: url(../../plugins/images/login-register.jpg) center center/cover no-repeat!important;*/ width: 500px; height: 100%; position: fixed } .new-login-register .lg-info-panel .inner-panel { position: absolute; height: 100%; width: 100%; background: rgba(0, 0, 0, .5) } .new-login-register .lg-info-panel .lg-content { margin-top: 50%; text-align: center; padding: 0 50px } .new-login-register .lg-info-panel .lg-content h2 { color: #fff } .new-login-register .lg-info-panel .lg-content p { padding: 20px 0; color: rgba(255, 255, 255, .7); font-style: italic } .new-login-register .new-login-box { margin-left: 50%; margin-top: 10%; width: 400px } .new-login-register .new-login-box .new-lg-form { padding-top: 20px } .new-login-register .new-login-box .new-lg-form label { text-transform: uppercase; font-size: 12px } .new-login-register .new-login-box .social { display: block; margin-bottom: 30px } .pricing-box { position: relative; text-align: center; margin-top: 30px } .featured-plan { margin-top: 0 } .featured-plan .pricing-body { padding: 60px 0; background: #f7fafc; border: 1px solid #ddd } .featured-plan .price-table-content .price-row { border-top: 1px solid rgba(120, 130, 140, .13) } .pricing-body { border-radius: 0; border-top: 1px solid rgba(120, 130, 140, .13); border-bottom: 5px solid rgba(120, 130, 140, .13); vertical-align: middle; padding: 30px 0; position: relative } .pricing-body h2 { position: relative; font-size: 56px; margin: 20px 0 10px; font-weight: 500 } .pricing-body h2 span { position: absolute; font-size: 15px; top: -10px; margin-left: -10px } .price-table-content .price-row { padding: 20px 0; border-top: 1px solid rgba(120, 130, 140, .13) } .pricing-plan { padding: 0 15px } .pricing-plan .no-padding { padding: 0 } .price-lable { position: absolute; top: -10px; padding: 5px 10px; margin: 0 auto; display: inline-block; width: 100px; left: 0; right: 0 } .mails a { color: #263238 } .mails td { vertical-align: middle!important; position: relative } .mails td:last-of-type { width: 100px; padding-right: 20px } .mails tr:hover .text-white { display: none } .mails .mail-select { padding: 12px 20px; min-width: 134px } .mails .checkbox { margin-bottom: 0; margin-top: 0; vertical-align: middle; display: inline-block; height: 17px } .mails .checkbox label { min-height: 16px } .mail-list .list-group-item { background-color: transparent; border: 0; border-left: 3px solid #fff; border-radius: 0 } .mail-list .list-group-item:hover { background: #f7fafc; border-left: 3px solid #f7fafc } .mail-list .list-group-item:focus { border-left: 3px solid #f7fafc } .mail-list .list-group-item.active:focus { background: #f7fafc; border-left: 3px solid #f33155 } .mail-list .list-group-item.active { border-left: 3px solid #f33155; border-radius: 0; color: #263238!important } .mail_listing { min-height: 500px } .inbox_listing .inbox-item:hover { background: #f7fafc } .inbox_listing .inbox-item { padding-left: 20px } .inbox-widget.inbox_listing .inbox-item .inbox-item-text { height: 19px; overflow: hidden } .message-center .unread .mail-contnet .mail-desc, .message-center .unread .mail-contnet h5 { font-weight: 600; color: #263238!important } .calendar { float: left; margin-bottom: 0 } .fc-view { margin-top: 30px } .none-border .modal-footer { border-top: none } .fc-toolbar h2 { font-size: 18px; font-weight: 600; line-height: 30px; text-transform: uppercase } .fc-day { background: #fff } .fc-toolbar .fc-state-active, .fc-toolbar .ui-state-active, .fc-toolbar .ui-state-hover, .fc-toolbar button:focus, .fc-toolbar button:hover { z-index: 0 } .fc-widget-header { border: 0!important } .fc-widget-content { border-color: rgba(120, 130, 140, .13)!important } .fc th.fc-widget-header { color: #fff; font-size: 14px; line-height: 20px; padding: 7px 0; text-transform: uppercase } .fc th.fc-sat, .fc th.fc-sun, .fc th.fc-thu, .fc th.fc-tue { background: #34b6ef } .fc th.fc-fri, .fc th.fc-mon, .fc th.fc-wed { background: #3bbcf5 } .fc-view { margin-top: 0 } .fc-toolbar { background: #41b3f9; margin: 0; padding: 24px 20px } .fc-toolbar h2 { color: #fff } .fc-button { background: #3bbcf5; border: 1px solid #41b3f9; color: #fff; text-transform: capitalize } .fc-button:hover { background: #3bbcf5; opacity: .8 } .fc-text-arrow { font-family: inherit; font-size: 16px } .fc-state-hover { background: #F5F5F5 } .fc-unthemed .fc-today { border: 1px solid #f33155; background: #f7fafc!important } .fc-cell-overlay, .fc-state-highlight { background: #f0f0f0 } .fc-event { border-radius: 0; border: none; cursor: move; font-size: 13px; margin: 1px -1px 0; padding: 5px; text-align: center; background: #41b3f9 } .calendar-event { cursor: move; margin: 10px 5px 0 0; padding: 6px 10px; display: inline-block; color: #fff; min-width: 140px; text-align: center; background: #41b3f9 } .calendar-event a { float: right; opacity: .6; font-size: 10px; margin: 4px 0 0 10px; color: #fff } .fc-basic-view td.fc-week-number span { padding-right: 5px } .fc-basic-view .fc-day-number { padding: 10px 15px; display: inline-block } .weather h1 { color: #fff; font-size: 50px; font-weight: 100 } .weather i { color: #fff; font-size: 40px } .weather .w-title-sub { color: rgba(255, 255, 255, .6) } @-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg) } to { -webkit-transform: rotate(360deg) } } @-moz-keyframes rotate { from { -moz-transform: rotate(0deg) } to { -moz-transform: rotate(360deg) } } @keyframes rotate { from { transform: rotate(0deg) } to { transform: rotate(360deg) } } .right-side-toggle { position: relative } .right-side-toggle i { -webkit-transition-property: -webkit-transform; -webkit-transition-duration: 1s; -moz-transition-property: -moz-transform; -moz-transition-duration: 1s; transition-property: transform; transition-duration: 1s; -webkit-animation-name: rotate; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; -moz-animation-name: rotate; -moz-animation-duration: 2s; -moz-animation-iteration-count: infinite; -moz-animation-timing-function: linear; animation-name: rotate; animation-duration: 2s; animation-iteration-count: infinite; animation-timing-function: linear; position: absolute; top: 7px; left: 8px } .right-sidebar { position: fixed; right: -240px; width: 240px; display: none; z-index: 1200; background: #fff; top: 0; height: 100%; box-shadow: 5px 1px 40px rgba(0, 0, 0, .1); transition: all .3s ease } .right-sidebar .rpanel-title { display: block; padding: 21px; color: #fff; text-transform: uppercase; font-size: 13px; background: #2cabe3 } .right-sidebar .rpanel-title span { float: right; cursor: pointer; font-size: 11px } .right-sidebar .rpanel-title span:hover { color: #263238 } .right-sidebar .r-panel-body { padding: 20px } .right-sidebar .r-panel-body ul { margin: 0; padding: 0 } .right-sidebar .r-panel-body ul li { list-style: none; padding: 5px 0 } .shw-rside { right: 0; width: 240px; display: block } .chatonline img { margin-right: 10px; float: left; width: 30px } .chatonline li a { padding: 13px 0; float: left; width: 100% } .chatonline li a span { color: #313131 } .chatonline li a span small { display: block; font-size: 10px } ul#themecolors { display: block } ul#themecolors li { display: inline-block } ul#themecolors li:first-child { display: block } #themecolors li a { width: 50px; height: 50px; display: inline-block; margin: 5px; color: transparent; position: relative } #themecolors li a.working:before { content: "\f00c"; font-family: FontAwesome; font-size: 18px; line-height: 50px; width: 50px; height: 50px; position: absolute; top: 0; left: 0; color: #fff; text-align: center } .default-theme { background: #4c5667 } .green-theme { background: #7ace4c } .yellow-theme { background: #a0aec4 } .blue-theme { background: #41b3f9 } .purple-theme { background: #707cd2 } .megna-theme { background: #e4e7ea } .default-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #f33155 23%, #f33155 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #f33155 23%, #f33155 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #f33155 23%, #f33155 99%) } .green-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #00c292 23%, #00c292 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #00c292 23%, #00c292 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #00c292 23%, #00c292 99%) } .yellow-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #a0aec4 23%, #a0aec4 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #a0aec4 23%, #a0aec4 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #a0aec4 23%, #a0aec4 99%) } .blue-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #41b3f9 23%, #41b3f9 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #41b3f9 23%, #41b3f9 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #41b3f9 23%, #41b3f9 99%) } .purple-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #707cd2 23%, #707cd2 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #707cd2 23%, #707cd2 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #707cd2 23%, #707cd2 99%) } .megna-dark-theme { background: #4f5467; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #e4e7ea 23%, #e4e7ea 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #e4e7ea 23%, #e4e7ea 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #e4e7ea 23%, #e4e7ea 99%) } .red-dark-theme { background: #e20b0b; background: -moz-linear-gradient(left, #4f5467 0, #4f5467 23%, #e20b0b 23%, #e20b0b 99%); background: -webkit-linear-gradient(left, #4f5467 0, #4f5467 23%, #e20b0b 23%, #e20b0b 99%); background: linear-gradient(to right, #4f5467 0, #4f5467 23%, #e20b0b 23%, #e20b0b 99%) } .visited li a { color: #313131 } .visited li.active a { color: #2cabe3 } .stats-row { margin-bottom: 20px } .stat-item { display: inline-block; padding-right: 15px } .stat-item+.stat-item { padding-left: 15px; border-left: 1px solid #eee } .country-state { list-style: none; margin: 0; padding: 0 0 0 10px } .country-state h2 { margin: 0 } .country-state .progress { margin-top: 8px } .two-part li { width: 48.8% } .two-part li i { font-size: 50px } .two-part li span { font-size: 50px; font-weight: 100; font-family: Rubik, sans-serif } .news-slide { position: relative } .news-slide .overlaybg { height: 370px; overflow: hidden } .news-slide .overlaybg img { width: 100%; height: 100% } .news-slide .news-content { position: absolute; height: 370px; background: rgba(0, 0, 0, .5); z-index: 10; width: 100%; top: 0; padding: 30px } .news-slide .news-content h2 { height: 240px; overflow: hidden; color: #fff } .news-slide .news-content a { color: #fff; opacity: .6; text-transform: uppercase } .news-slide .news-content a:hover { opacity: 1 } .dashboard-slide .news-content, .dashboard-slide .overlaybg { height: 435px } .dashboard-slide .news-content h2 { height: 320px } .nav-pills-rounded li { display: inline-block; float: none } .nav-pills-rounded li a { border-radius: 60px; -moz-border-radius: 60px; -webkit-border-radius: 60px; color: #313131; padding: 10px 25px } .nav-pills-rounded li.active a, .nav-pills-rounded li.active a:focus, .nav-pills-rounded li.active a:hover { background: #2cabe3; color: #fff } .analytics-info .list-inline { margin-bottom: 0 } .analytics-info .list-inline li { vertical-align: middle; display: block; margin-right: 0; } .analytics-info .list-inline li span { font-size: 24px } .analytics-info .list-inline li i { font-size: 20px } .feeds { margin: 0; padding: 0 } .feeds li { list-style: none; padding: 10px; display: block } .feeds li:hover { background: #f7fafc } .feeds li>div { width: 40px; height: 40px; margin-right: 5px; display: inline-block; text-align: center; vertical-align: middle; border-radius: 100% } .feeds li>div i { line-height: 40px } .feeds li span { float: right; width: auto; font-size: 12px } .jq-icon-info { background-color: #41b3f9; color: #fff } .jq-icon-success { background-color: #7ace4c; color: #fff } .jq-icon-error { background-color: #f33155; color: #fff } .jq-icon-warning { background-color: #fb4; color: #fff } .dropzone { border-style: dashed; border-width: 1px } .weather h1 sup { font-size: 20px; top: -1.2em } .fcbtn { position: relative; -webkit-transition: all .3s; -moz-transition: all .3s; transition: all .3s; padding: 8px 20px } .fcbtn:after { content: ''; position: absolute; z-index: -1; -webkit-transition: all .3s; -moz-transition: all .3s; transition: all .3s } .btn-1b:after { width: 100%; height: 0; top: 0; left: 0 } .btn-1b:active, .btn-1b:hover { color: #fff } .btn-1b:active:after, .btn-1b:hover:after { height: 100% } .btn-1b.btn-info:after, .btn-1c.btn-info:after, .btn-1d.btn-info:after, .btn-1e.btn-info:after, .btn-1f.btn-info:after { background: #41b3f9 } .btn-1b.btn-warning:after, .btn-1c.btn-warning:after, .btn-1d.btn-warning:after, .btn-1e.btn-warning:after, .btn-1f.btn-warning:after { background: #fb4 } .btn-1b.btn-danger:after, .btn-1c.btn-danger:after, .btn-1d.btn-danger:after, .btn-1e.btn-danger:after, .btn-1f.btn-danger:after { background: #f33155 } .btn-1b.btn-primary:after, .btn-1c.btn-primary:after, .btn-1d.btn-primary:after, .btn-1e.btn-primary:after, .btn-1f.btn-primary:after { background: #707cd2 } .btn-1b.btn-success:after, .btn-1c.btn-success:after, .btn-1d.btn-success:after, .btn-1e.btn-success:after, .btn-1f.btn-success:after { background: #7ace4c } .btn-1b.btn-inverse:after, .btn-1c.btn-inverse:after, .btn-1d.btn-inverse:after, .btn-1e.btn-inverse:after, .btn-1f.btn-inverse:after { background: #4c5667 } .btn-1c:after { width: 0; height: 100%; top: 0; left: 0 } .btn-1c:active, .btn-1c:hover { color: #000 } .btn-1c:active:after, .btn-1c:hover:after { width: 100% } .btn-1d { overflow: hidden } .btn-1d:after { width: 0; height: 103%; top: 50%; left: 50%; opacity: 0; -webkit-transform: translateX(-50%) translateY(-50%); -moz-transform: translateX(-50%) translateY(-50%); -ms-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%) } .btn-1d:hover:after { width: 100%; opacity: 1 } .btn-1e { overflow: hidden } .btn-1e:after { width: 100%; height: 0; top: 50%; left: 50%; background: #fff; opacity: 0; -webkit-transform: translateX(-50%) translateY(-50%) rotate(45deg); -moz-transform: translateX(-50%) translateY(-50%) rotate(45deg); -ms-transform: translateX(-50%) translateY(-50%) rotate(45deg); transform: translateX(-50%) translateY(-50%) rotate(45deg) } .btn-1e:hover:after { height: 260%; opacity: 1 } .btn-1e:active:after { height: 400%; opacity: 1 } .btn-1f { overflow: hidden } .btn-1f:after { width: 101%; height: 0; top: 50%; left: 50%; background: #fff; opacity: 0; -webkit-transform: translateX(-50%) translateY(-50%); -moz-transform: translateX(-50%) translateY(-50%); -ms-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%) } .btn-1f:hover:after { height: 100%; opacity: 1 } .btn-1f:active:after { height: 130%; opacity: 1 } .sweet-alert { padding: 25px } .sweet-alert h2 { margin-top: 0 } .sweet-alert p { line-height: 30px } ul.list-icons { margin: 0; padding: 0 } ul.list-icons li { list-style: none; line-height: 40px } ul.list-icons li i { font-size: 12px; margin-right: 5px } .demo-popover .popover, .demo-tooltip .tooltip { position: relative; margin-right: 25px; opacity: 1; display: inline-block } .tooltip-inner { border-radius: 3px; padding: 5px 10px } .tooltip.in { opacity: 1 } .tooltip-primary+.tooltip .tooltip-inner, .tooltip-primary.tooltip .tooltip-inner { color: #fff; background-color: #7460ee } .tooltip-primary+.tooltip.top .tooltip-arrow, .tooltip-primary.tooltip.top .tooltip-arrow { border-top-color: #7460ee } .tooltip-primary+.tooltip.right .tooltip-arrow, .tooltip-primary.tooltip.right .tooltip-arrow { border-right-color: #7460ee } .tooltip-primary+.tooltip.bottom .tooltip-arrow, .tooltip-primary.tooltip.bottom .tooltip-arrow { border-bottom-color: #7460ee } .tooltip-primary+.tooltip.left .tooltip-arrow, .tooltip-primary.tooltip.left .tooltip-arrow { border-left-color: #7460ee } .tooltip-success+.tooltip .tooltip-inner, .tooltip-success.tooltip .tooltip-inner { color: #fff; background-color: #7ace4c } .tooltip-success+.tooltip.top .tooltip-arrow, .tooltip-success.tooltip.top .tooltip-arrow { border-top-color: #7ace4c } .tooltip-success+.tooltip.right .tooltip-arrow, .tooltip-success.tooltip.right .tooltip-arrow { border-right-color: #7ace4c } .tooltip-success+.tooltip.bottom .tooltip-arrow, .tooltip-success.tooltip.bottom .tooltip-arrow { border-bottom-color: #7ace4c } .tooltip-success+.tooltip.left .tooltip-arrow, .tooltip-success.tooltip.left .tooltip-arrow { border-left-color: #7ace4c } .tooltip-warning+.tooltip .tooltip-inner, .tooltip-warning.tooltip .tooltip-inner { color: #fff; background-color: #fb4 } .tooltip-warning+.tooltip.top .tooltip-arrow, .tooltip-warning.tooltip.top .tooltip-arrow { border-top-color: #fb4 } .tooltip-warning+.tooltip.right .tooltip-arrow, .tooltip-warning.tooltip.right .tooltip-arrow { border-right-color: #fb4 } .tooltip-warning+.tooltip.bottom .tooltip-arrow, .tooltip-warning.tooltip.bottom .tooltip-arrow { border-bottom-color: #fb4 } .tooltip-warning+.tooltip.left .tooltip-arrow, .tooltip-warning.tooltip.left .tooltip-arrow { border-left-color: #fb4 } .tooltip-info+.tooltip .tooltip-inner, .tooltip-info.tooltip .tooltip-inner { color: #fff; background-color: #41b3f9 } .tooltip-info+.tooltip.top .tooltip-arrow, .tooltip-info.tooltip.top .tooltip-arrow { border-top-color: #41b3f9 } .tooltip-info+.tooltip.right .tooltip-arrow, .tooltip-info.tooltip.right .tooltip-arrow { border-right-color: #41b3f9 } .tooltip-info+tooltip.bottom .tooltip-arrow, .tooltip-info.tooltip.bottom .tooltip-arrow { border-bottom-color: #41b3f9 } .tooltip-info+.tooltip.left .tooltip-arrow, .tooltip-info.tooltip.left .tooltip-arrow { border-left-color: #41b3f9 } .tooltip-danger+.tooltip .tooltip-inner, .tooltip-danger.tooltip .tooltip-inner { color: #fff; background-color: #f33155 } .tooltip-danger+.tooltip.top .tooltip-arrow, .tooltip-danger.tooltip.top .tooltip-arrow { border-top-color: #f33155 } .tooltip-danger+.tooltip.right .tooltip-arrow, .tooltip-danger.tooltip.right .tooltip-arrow { border-right-color: #f33155 } .tooltip-danger+.tooltip.bottom .tooltip-arrow, .tooltip-danger.tooltip.bottom .tooltip-arrow { border-bottom-color: #f33155 } .tooltip-danger+.tooltip.left .tooltip-arrow, .tooltip-danger.tooltip.left .tooltip-arrow { border-left-color: #f33155 } .flotTip { padding: 8px 12px; background-color: #263238; z-index: 100; color: #fff; opacity: .9; font-size: 13px } .popover { -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, .05); box-shadow: 0 2px 6px rgba(0, 0, 0, .05) } .popover .popover-title { border-radius: 0 } .popover-primary+.popover .popover-title { color: #fff; background-color: #7460ee; border-color: #7460ee } .popover-primary+.popover.bottom .arrow, .popover-primary+.popover.bottom .arrow:after { border-bottom-color: #7460ee } .popover-success+.popover .popover-title { color: #fff; background-color: #7ace4c; border-color: #7ace4c } .popover-success+.popover.bottom .arrow, .popover-success+.popover.bottom .arrow:after { border-bottom-color: #7ace4c } .popover-info+.popover .popover-title { color: #fff; background-color: #41b3f9; border-color: #41b3f9 } .popover-info+.popover.bottom .arrow, .popover-info+.popover.bottom .arrow:after { border-bottom-color: #41b3f9 } .popover-warning+.popover .popover-title { color: #fff; background-color: #fb4; border-color: #fb4 } .popover-warning+.popover.bottom .arrow, .popover-warning+.popover.bottom .arrow:after { border-bottom-color: #fb4 } .popover-danger+.popover .popover-title { color: #fff; background-color: #f33155; border-color: #f33155 } .popover-danger+.popover.bottom .arrow, .popover-danger+.popover.bottom .arrow:after { border-bottom-color: #f33155 } .btn-file { overflow: hidden; position: relative; vertical-align: middle } .btn-file>input { position: absolute; top: 0; right: 0; margin: 0; opacity: 0; filter: alpha(opacity=0); font-size: 23px; height: 100%; width: 100%; direction: ltr; cursor: pointer; border-radius: 0 } .fileinput { margin-bottom: 9px; display: inline-block } .fileinput .form-control { padding-top: 7px; padding-bottom: 5px; display: inline-block; margin-bottom: 0; vertical-align: middle; cursor: text } .fileinput .thumbnail { overflow: hidden; display: inline-block; margin-bottom: 5px; vertical-align: middle; text-align: center } .fileinput .thumbnail>img { max-height: 100% } .fileinput .btn { vertical-align: middle } .fileinput-exists .fileinput-new, .fileinput-new .fileinput-exists { display: none } .fileinput-inline .fileinput-controls { display: inline } .fileinput-filename { vertical-align: middle; display: inline-block; overflow: hidden } .form-control .fileinput-filename { vertical-align: bottom } .fileinput.input-group { display: table } .fileinput.input-group>* { position: relative; z-index: 2 } .fileinput.input-group>.btn-file { z-index: 1 } .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) { width: 100% } .ms-container .ms-list { border-radius: 0; box-shadow: none } .ms-container .ms-selectable li.ms-elem-selectable, .ms-container .ms-selection li.ms-elem-selection { padding: 6px 10px } .ms-container .ms-selectable li.ms-hover, .ms-container .ms-selection li.ms-hover { background: #41b3f9 } .dropzone .dz-message { text-align: center; margin: 10% 0 } .editable-input .form-control { height: 30px } .asColorPicker-trigger { position: absolute; top: 0; right: -35px; height: 38px; width: 37px; border: 0 } .asColorPicker-dropdown { max-width: 260px } .asColorPicker-clear { top: 7px; right: 16px } .datepicker table tr td.today, .datepicker table tr td.today.disabled, .datepicker table tr td.today.disabled:hover, .datepicker table tr td.today:hover { background: #2cabe3; color: #fff } .datepicker table tr td.active, .datepicker table tr td.active.disabled, .datepicker table tr td.active.disabled:hover, .datepicker table tr td.active:hover { background: #41b3f9; color: #fff } .editable-table+input.error { border: 1px solid #danger; outline: 0; outline-offset: 0 } #editable-datatable_wrapper+input:focus, .editable-table+input, .editable-table+input:focus { border: 1px solid #41b3f9!important; outline: 0!important; outline-offset: 0!important } .editable-table td:focus { outline: 0 } .user-profile { padding: 70px 0 15px; position: relative; text-align: center } .user-profile .user-pro-body { display: block } .user-profile .user-pro-body img { width: 50px; display: block; margin: 0 auto 10px } .user-profile .user-pro-body .u-dropdown { color: #97999f } .user-profile .user-pro-body .dropdown-menu { right: 0; width: 180px; left: 0; margin: 0 auto } .wizard-steps { display: table; width: 100% } .wizard-steps>li { display: table-cell; padding: 10px 20px; background: #f7fafc } .wizard-steps>li span { border-radius: 100%; border: 1px solid rgba(120, 130, 140, .13); width: 40px; height: 40px; display: inline-block; vertical-align: middle; padding-top: 9px; margin-right: 8px; text-align: center } .wizard-content { padding: 25px; border-color: rgba(120, 130, 140, .13); margin-bottom: 30px } .wizard-steps>li.current, .wizard-steps>li.done { background: #41b3f9; color: #fff } .wizard-steps>li.current span, .wizard-steps>li.done span { border-color: #fff; color: #fff } .wizard-steps>li.current h4, .wizard-steps>li.done h4 { color: #fff } .wizard-steps>li.done { background: #7ace4c } .wizard-steps>li.error { background: #f33155 } .wiz-aco .pager { margin: 0 } #morris-donut-chart svg text { font-family: Rubik, sans-serif!important; font-weight: 400!important } #diagram { margin: 0 auto; width: 250px; padding-top: 30px; height: 271px } #diagram circle { fill: #fff } #diagram text { fill: #313131 } .get { display: none } ul.expense-box { margin: 0; padding: 0 } ul.expense-box li { list-style: none; display: inline-block; padding: 8px 0 8px 20px } ul.expense-box li i { width: 60px; font-size: 30px; vertical-align: middle; display: inline-block } ul.expense-box li div, ul.expense-box li span { display: inline-block; vertical-align: middle } ul.expense-box li div h2, ul.expense-box li span h2 { margin-bottom: 0; font-weight: 400 } ul.expense-box li div h4, ul.expense-box li span h4 { margin-top: 0 } .minus-margin { margin: 0 -25px } .manage-users { margin-bottom: 30px } .manage-users .tabs-style-iconbox nav { background: #41b3f9 } .manage-users .tabs-style-iconbox nav ul li a { color: rgba(255, 255, 255, .6); text-transform: uppercase } .manage-users .tabs-style-iconbox nav ul li a.sticon:before { margin-bottom: 15px } .manage-users .tabs-style-iconbox nav ul li.tab-current a { box-shadow: none } ul.side-icon-text { margin: 0; padding: 0 } ul.side-icon-text>li { list-style: none; display: inline-block; margin-right: 10px } ul.side-icon-text>li a { color: #313131; font-weight: 400 } ul.side-icon-text>li a:hover { color: #41b3f9 } ul.side-icon-text>li a span { margin-right: 10px } .manage-table { border-top: 1px solid rgba(120, 130, 140, .13); margin: 10px -25px 0; background: #f7fafc; padding: 30px } .table tbody tr.advance-table-row { border: 2px solid rgba(120, 130, 140, .13); white-space: nowrap } .table tbody tr.advance-table-row .checkbox { margin: 0 } .table tbody tr.advance-table-row.active { border: 2px solid #2cabe3 } .table tbody tr.advance-table-row td { vertical-align: middle!important; border: 0!important; font-size: 16px; background: #fff } td.sm-pd { padding: 5px 0!important } .demo-container .flot-text, .demo-container .flot-x-axis, .wallet-widgets #morris-area-chart2 text { display: none } ul.wallet-list { margin: 0; padding: 0 } ul.wallet-list li { list-style: none; display: block; font-size: 18px; padding: 20px; border-top: 1px solid rgba(120, 130, 140, .13) } ul.wallet-list li i { font-size: 24px; display: inline-block; margin-right: 12px; vertical-align: middle; color: #41b3f9 } ul.wallet-list li a { vertical-align: middle; color: #313131 } ul.wallet-list li a:hover { color: #2cabe3 } @keyframes dasharray-craziness { 0% { stroke-dasharray: 5px } 50% { stroke-dasharray: 6px } 100% { stroke-dasharray: 7px } } #ct-bar-chart, #ct-city-wth, #ct-daily-sales, #ct-extra, #ct-main-bal, #ct-polar-chart, #ct-sales, #ct-visits, #ct-weather { position: relative } #ct-extra .ct-series-a .ct-line, #ct-extra .ct-series-a .ct-point, #ct-sales .ct-series-a .ct-line, #ct-sales .ct-series-a .ct-point, #ct-weather .ct-series-a .ct-line, #ct-weather .ct-series-a .ct-point { stroke: #fff; stroke-shadow: 3px 10px 10px #000 } #ct-extra .ct-series-a .ct-area, #ct-sales .ct-series-a .ct-area, #ct-weather .ct-series-a .ct-area { fill: none } #ct-extra .ct-grid, #ct-sales .ct-grid, #ct-weather .ct-grid { stroke: rgba(255, 255, 255, .2); stroke-dasharray: 0 } #ct-weather .ct-series-a .ct-line { animation: dasharray-craziness 2s infinite } .ct-label { font-size: 1em } #ct-extra .ct-series-a .ct-line, #ct-extra .ct-series-a .ct-point { stroke: #41b3f9; animation: dasharray-craziness .5s infinite } #ct-extra .ct-grid { stroke: rgba(0, 0, 0, .2); stroke-dasharray: 2px } #ct-bar-chart .ct-series-a .ct-bar { stroke: #41b3f9; stroke-width: 7px } #ct-main-bal .ct-series-a .ct-line, #ct-main-bal .ct-series-a .ct-point { stroke: none; fill: #41b3f9; fill-opacity: .5 } #ct-main-bal .ct-series-b .ct-line, #ct-main-bal .ct-series-b .ct-point { stroke: #41b3f9; stroke-width: 1px; animation: dasharray-craziness 2s infinite; opacity: .8 } #ct-main-bal .ct-series-b .ct-area { fill: #41b3f9; fill-opacity: .2 } #ct-visits .ct-series-a .ct-line, #ct-visits .ct-series-a .ct-point { stroke: #98a6ad } #ct-visits .ct-series-b .ct-line, #ct-visits .ct-series-b .ct-point { stroke: #41b3f9 } #ct-visits .ct-series-a .ct-area { fill: #98a6ad; fill-opacity: .05 } #ct-visits .ct-series-b .ct-area { fill: #41b3f9; fill-opacity: .1 } #ct-visits .ct-line { stroke-width: 2px } #ct-city-wth .ct-label { color: #fff } #ct-city-wth .ct-series-a .ct-line, #ct-city-wth .ct-series-a .ct-point { stroke: #41b3f9 } #ct-city-wth .ct-series-a .ct-area { fill: none } #ct-polar-chart .ct-series-a .ct-point, #ct-polar-chart .ct-series-b .ct-point, #ct-polar-chart .ct-series-c .ct-point, #ct-polar-chart .ct-series-d .ct-point { stroke-width: 3px } #ct-polar-chart .ct-series-a .ct-area { fill: #41b3f9 } #ct-polar-chart .ct-series-b .ct-area { fill: #7ace4c } #ct-polar-chart .ct-series-c .ct-area { fill: #f33155 } #ct-polar-chart .ct-series-d .ct-area { fill: #fb4 } #ct-daily-sales .ct-series-a .ct-bar { stroke: rgba(255, 255, 255, .7); stroke-width: 10px } .dp-table { display: table; width: 100%; margin: 0; padding: 0 } .dp-table li { margin: 0; padding: 0; list-style: none; display: table-cell; text-align: center } .calendar-widget { display: block; background: #fff; overflow: hidden } .calendar-widget .cal-left { width: 30%; float: left; position: absolute; padding: 5%; height: 100% } .calendar-widget .cal-left .cal-btm-text { position: absolute; bottom: 40px; font-weight: 400 } .calendar-widget .cal-left h1 { font-size: 50px; margin-bottom: 0; font-weight: 400 } .calendar-widget .cal-left span { width: 100px; border-top: 2px solid #7ace4c; height: 2px; margin: 3px 0; display: inline-block } .calendar-widget .cal-right { width: 70%; float: right; min-height: 200px } .calendar-widget .cal-right .cal-table { width: 100% } .calendar-widget .cal-right .cal-table td { padding: 18px 15px; text-align: center; font-weight: 400 } .calendar-widget .cal-right .cal-table td h1 { text-align: left; font-weight: 400; padding-left: 30px } .calendar-widget .cal-right .cal-table td .cal-add { font-size: 24px } .calendar-widget .cal-right .cal-table td.cal-active { border-radius: 60px; background: rgba(0, 0, 0, .1) } .real-time-widgets { text-align: center; position: relative } .real-time-widgets .data-text { width: 200px; margin: 0 auto; position: absolute; left: 0; z-index: 200; right: 0; top: 110px } .real-time-widgets .data-text h1 { font-size: 50px } .real-time-widgets .data-text h5 { width: 70px; margin: 0 auto 10px; padding-bottom: 8px; border-bottom: 2px solid #7ace4c } .real-time-widgets .data-text span { font-size: 18px; font-weight: 400 } .profile-social-icons { padding-bottom: 30px; font-size: 20px } .profile-social-icons a { color: #98a6ad } .mailbox-widget .customtab { border-bottom: 0 } .mailbox-widget .customtab li a { color: #fff } .mailbox-widget .customtab li a:hover { background: 0 0; opacity: .5 } .mailbox-widget .customtab li.active a, .mailbox-widget .customtab li.active a:focus { background: 0 0; color: #fff; border-color: #7ace4c } .sk-chat-widgets .chatonline { padding: 0 } .sk-chat-widgets .chatonline li { list-style: none; padding: 5px 0; position: relative } .sk-chat-widgets .chatonline li a { float: none; display: inline-block } .sk-chat-widgets .chatonline li a img { width: 40px } .sk-chat-widgets .chatonline li .call-chat { position: absolute; right: 0; display: none; top: 20px } .sk-chat-widgets .chatonline li:hover .call-chat { display: block } .chat-box-input { border: 0; width: 100%; height: 60px; resize: none; line-height: 24px } .manage-u-table select { max-width: 150px; border-radius: 60px } .manage-u-table td { white-space: nowrap } .city-weather-widget .side-icon-text i { font-size: 50px; margin-right: 15px } .city-weather-widget .side-icon-text h1 { font-weight: 500 } .city-weather-days { padding: 0 15px } .city-weather-days li { text-align: center; font-size: 16px; padding: 18px 0; border-left: 1px solid rgba(120, 130, 140, .13); border-top: 1px solid rgba(120, 130, 140, .13) } .city-weather-days li span { display: block; text-transform: uppercase; line-height: 24px; padding: 7px 0 } .city-weather-days li i { font-size: 30px; color: #e8e8e8 } .city-weather-days li.active { border-bottom: 2px solid #f33155 } .city-weather-days li.active i { color: #f33155 } .weather-with-bg .wt-top .wt-img { width: 100%; height: 350px; padding: 40px 60px; background-size: cover; background-position: center center; overflow: hidden } .weather-with-bg .wt-top .wt-img h1, .weather-with-bg .wt-top .wt-img h4, .weather-with-bg .wt-top .wt-img i { color: #fff } .weather-with-bg .wt-top .wt-img .side-icon-text li i { font-size: 60px; margin-right: 20px } .weather-with-bg .wt-top .wt-img .side-icon-text li h1 { font-size: 60px } .weather-with-bg .wt-top .wt-img .wt-city-text { padding-top: 50px } .weather-with-bg .wt-counter li { display: inline-block; padding: 10px 7.5px } .weather-with-bg .wt-counter li a { min-width: 50px; display: block; padding: 13px; height: 50px; color: #313131; font-size: 17px; text-align: center; border-radius: 100% } .weather-with-bg .wt-counter li.active a { background: #2cabe3; color: #fff } .mt-gauge { background: #fff; height: 314px } .calendar-events { padding: 8px 10px; border: 1px solid #fff; cursor: move } .calendar-events:hover { border: 1px dashed rgba(120, 130, 140, .13) } .calendar-events i { margin-right: 8px } .earning-box { padding: 0; margin: 0 } .earning-box li { display: box; list-style: none; padding: 20px 0 } .earning-box li .er-row { overflow: hidden } .earning-box li .er-row .er-pic { float: left; margin-right: 20px } .earning-box li .er-row .er-pic img { width: 60px } .earning-box li .er-row .er-text { float: left; width: 45% } .earning-box li .er-row .er-text h3 { margin: 5px 0 0; font-weight: 400; font-size: 18px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden } .earning-box li .er-row .er-count { float: right; font-size: 30px; padding-top: 5px; color: #41b3f9; font-weight: 400 } .todo-list li { border: 0; border-bottom: 1px solid rgba(120, 130, 140, .13); margin-bottom: 0; padding: 20px 15px 15px 0 } .todo-list li .checkbox label { font-weight: 400 } .todo-list li:last-child { border-bottom: 0 } .todo-list li .assignedto { padding: 0 0 0 27px; margin: 0 } .todo-list li .assignedto li { list-style: none; padding: 0; display: inline-block; border: 0; margin-right: 2px } .todo-list li .assignedto li img { width: 30px; border-radius: 100% } .todo-list li .item-date { padding-left: 25px; font-size: 12px; display: inline-block } .list-task .task-done span { text-decoration: line-through } .no-bg-addon .input-group-addon { background-color: #fff; border: 1px solid rgba(120, 130, 140, .13); left: -2px; position: relative; z-index: 10; border-left: 0; color: #e4e7ea; border-radius: 0 3px 3px 0 } .no-bg-addon .form-control { transition: 0s } .no-bg-addon .form-control:focus+.input-group-addon { border-color: #313131; color: #313131 } .select-mode .btn { padding: 15px 0 } .select-mode .btn.btn-default:focus { border-color: #41b3f9; color: #fff; background: #41b3f9 } ul.select-row-icon { padding: 0; margin: 0 } ul.select-row-icon li { display: block; list-style: none } ul.select-row-icon li a { display: block; color: #313131; padding: 8px 15px; position: relative; border: 2px solid #fff } ul.select-row-icon li a i { font-size: 24px; vertical-align: middle; padding-right: 10px } ul.select-row-icon li a i.whn-hov { color: #41b3f9; display: none; float: right; position: absolute; right: 15px; top: 10px } ul.select-row-icon li a.selected, ul.select-row-icon li a:hover { border: 2px solid rgba(120, 130, 140, .13) } ul.select-row-icon li a.selected i.whn-hov, ul.select-row-icon li a:hover i.whn-hov { display: inline-block } .sidebar { overflow-y: auto } .sidebar .sidebar-nav.navbar-collapse { padding-left: 0; padding-right: 0 } .sidebar .fa-fw { width: 20px; text-align: center!important; display: inline-block; font-style: normal; font-weight: 500; margin-right: 7px; font-size: 16px; vertical-align: middle } .sidebar .mdi { font-size: 21px } .sidebar .sidebar-head { padding: 4px 20px; width: 240px; position: fixed; z-index: 10; left: 0; top: 0 } .sidebar .sidebar-head h3 { color: #fff; font-weight: 400 } .sidebar .sidebar-head h3 i { font-size: 20px } .sidebar:hover .sidebar-head { width: 240px } .sidebar .label { font-size: 10px; border-radius: 60px; padding: 6px 8px; min-width: 30px; height: 20px; margin-top: 0 } .sidebar #side-menu .user-pro .img-circle { width: 30px; margin-right: 10px } .sidebar #side-menu .user-pro>a { padding-left: 15px } .sidebar #side-menu .user-pro ul li a { padding-left: 25px } .sidebar #side-menu .user-pro .nav-second-level li i { margin-right: 10px } #side-menu { overflow: hidden } .sidebar .sidebar-search { padding: 15px } #side-menu li.active>a { background: rgba(0, 0, 0, 0) } #side-menu li a { color: #97999f; width: 240px } #side-menu li a:focus { background: rgba(0, 0, 0, 0) } #side-menu li.devider { margin: 7px 0; border-top: 1px solid rgba(120, 130, 140, .13) } #side-menu>li>a { padding: 15px 35px 15px 20px; display: block } #side-menu>li>a:focus, #side-menu>li>a:hover { background: rgba(0, 0, 0, .1) } #side-menu>li>a.active { color: #2cabe3 } #side-menu ul>li>a:hover { color: #2cabe3; background: 0 0 } #side-menu ul>li>a.active { color: #2cabe3 } .sidebar .arrow { position: absolute; right: 20px; top: 17px } .sidebar .nav-second-level .arrow { right: 20px; top: 17px } .sidebar .fa.arrow:before { content: "\f105" } .sidebar .active>a>span>.fa.arrow:before { content: "\f107" } .sidebar .nav-second-level li, .sidebar .nav-third-level li { border-bottom: none!important } .sidebar .nav-second-level li a { padding: 14px 10px 14px 40px } .sidebar .nav-third-level li a { padding-left: 60px } .content-wrapper .nicescroll-rails { display: none!important } /*! * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ @font-face { font-family: FontAwesome; /*src: url(../less/icons/font-awesome/fonts/fontawesome-webfont.eot?v=4.5.0);*/ /*src: url(../less/icons/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.5.0) format('embedded-opentype'), url(../less/icons/font-awesome/fonts/fontawesome-webfont.woff2?v=4.5.0) format('woff2'), url(../less/icons/font-awesome/fonts/fontawesome-webfont.woff?v=4.5.0) format('woff'), url(../less/icons/font-awesome/fonts/fontawesome-webfont.ttf?v=4.5.0) format('truetype'), url(../less/icons/font-awesome/fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular) format('svg');*/ font-weight: 400; font-style: normal } .fa { display: inline-block; font: normal normal normal 14px/1 FontAwesome; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale } .fa-lg { font-size: 1.33333333em; line-height: .75em; vertical-align: -15% } .fa-2x { font-size: 2em } .fa-3x { font-size: 3em } .fa-4x { font-size: 4em } .fa-5x { font-size: 5em } .fa-fw { text-align: center } .fa-ul { padding-left: 0; margin-left: 2.14285714em; list-style-type: none } .fa-ul>li { position: relative } .fa-li { position: absolute; left: -2.14285714em; width: 2.14285714em; top: .14285714em; text-align: center } .fa-li.fa-lg { left: -1.85714286em } .fa-border { padding: .2em .25em .15em; border: .08em solid #eee; border-radius: .1em } .fa-pull-left { float: left } .fa-pull-right { float: right } .fa.fa-pull-left { margin-right: .3em } .fa.fa-pull-right { margin-left: .3em } .pull-right { float: right } .pull-left { float: left } .fa.pull-left { margin-right: .3em } .fa.pull-right { margin-left: .3em } .fa-spin { -webkit-animation: fa-spin 2s infinite linear; animation: fa-spin 2s infinite linear } .fa-pulse { -webkit-animation: fa-spin 1s infinite steps(8); animation: fa-spin 1s infinite steps(8) } @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg) } 100% { -webkit-transform: rotate(359deg); transform: rotate(359deg) } } @keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg) } 100% { -webkit-transform: rotate(359deg); transform: rotate(359deg) } } .fa-rotate-90 { filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=1); -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg) } .fa-rotate-180 { filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=2); -webkit-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg) } .fa-rotate-270 { filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=3); -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg) } .fa-flip-horizontal { filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); -webkit-transform: scale(-1, 1); -ms-transform: scale(-1, 1); transform: scale(-1, 1) } .fa-flip-vertical { filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); -webkit-transform: scale(1, -1); -ms-transform: scale(1, -1); transform: scale(1, -1) } :root .fa-flip-horizontal, :root .fa-flip-vertical, :root .fa-rotate-180, :root .fa-rotate-270, :root .fa-rotate-90 { filter: none } .fa-stack { position: relative; display: inline-block; width: 2em; height: 2em; line-height: 2em; vertical-align: middle } .fa-stack-1x, .fa-stack-2x { position: absolute; left: 0; width: 100%; text-align: center } .fa-stack-1x { line-height: inherit } .fa-stack-2x { font-size: 2em } .fa-inverse { color: #fff } .fa-glass:before { content: "\f000" } .fa-music:before { content: "\f001" } .fa-search:before { content: "\f002" } .fa-envelope-o:before { content: "\f003" } .fa-heart:before { content: "\f004" } .fa-star:before { content: "\f005" } .fa-star-o:before { content: "\f006" } .fa-user:before { content: "\f007" } .fa-film:before { content: "\f008" } .fa-th-large:before { content: "\f009" } .fa-th:before { content: "\f00a" } .fa-th-list:before { content: "\f00b" } .fa-check:before { content: "\f00c" } .fa-close:before, .fa-remove:before, .fa-times:before { content: "\f00d" } .fa-search-plus:before { content: "\f00e" } .fa-search-minus:before { content: "\f010" } .fa-power-off:before { content: "\f011" } .fa-signal:before { content: "\f012" } .fa-cog:before, .fa-gear:before { content: "\f013" } .fa-trash-o:before { content: "\f014" } .fa-home:before { content: "\f015" } .fa-file-o:before { content: "\f016" } .fa-clock-o:before { content: "\f017" } .fa-road:before { content: "\f018" } .fa-download:before { content: "\f019" } .fa-arrow-circle-o-down:before { content: "\f01a" } .fa-arrow-circle-o-up:before { content: "\f01b" } .fa-inbox:before { content: "\f01c" } .fa-play-circle-o:before { content: "\f01d" } .fa-repeat:before, .fa-rotate-right:before { content: "\f01e" } .fa-refresh:before { content: "\f021" } .fa-list-alt:before { content: "\f022" } .fa-lock:before { content: "\f023" } .fa-flag:before { content: "\f024" } .fa-headphones:before { content: "\f025" } .fa-volume-off:before { content: "\f026" } .fa-volume-down:before { content: "\f027" } .fa-volume-up:before { content: "\f028" } .fa-qrcode:before { content: "\f029" } .fa-barcode:before { content: "\f02a" } .fa-tag:before { content: "\f02b" } .fa-tags:before { content: "\f02c" } .fa-book:before { content: "\f02d" } .fa-bookmark:before { content: "\f02e" } .fa-print:before { content: "\f02f" } .fa-camera:before { content: "\f030" } .fa-font:before { content: "\f031" } .fa-bold:before { content: "\f032" } .fa-italic:before { content: "\f033" } .fa-text-height:before { content: "\f034" } .fa-text-width:before { content: "\f035" } .fa-align-left:before { content: "\f036" } .fa-align-center:before { content: "\f037" } .fa-align-right:before { content: "\f038" } .fa-align-justify:before { content: "\f039" } .fa-list:before { content: "\f03a" } .fa-dedent:before, .fa-outdent:before { content: "\f03b" } .fa-indent:before { content: "\f03c" } .fa-video-camera:before { content: "\f03d" } .fa-image:before, .fa-photo:before, .fa-picture-o:before { content: "\f03e" } .fa-pencil:before { content: "\f040" } .fa-map-marker:before { content: "\f041" } .fa-adjust:before { content: "\f042" } .fa-tint:before { content: "\f043" } .fa-edit:before, .fa-pencil-square-o:before { content: "\f044" } .fa-share-square-o:before { content: "\f045" } .fa-check-square-o:before { content: "\f046" } .fa-arrows:before { content: "\f047" } .fa-step-backward:before { content: "\f048" } .fa-fast-backward:before { content: "\f049" } .fa-backward:before { content: "\f04a" } .fa-play:before { content: "\f04b" } .fa-pause:before { content: "\f04c" } .fa-stop:before { content: "\f04d" } .fa-forward:before { content: "\f04e" } .fa-fast-forward:before { content: "\f050" } .fa-step-forward:before { content: "\f051" } .fa-eject:before { content: "\f052" } .fa-chevron-left:before { content: "\f053" } .fa-chevron-right:before { content: "\f054" } .fa-plus-circle:before { content: "\f055" } .fa-minus-circle:before { content: "\f056" } .fa-times-circle:before { content: "\f057" } .fa-check-circle:before { content: "\f058" } .fa-question-circle:before { content: "\f059" } .fa-info-circle:before { content: "\f05a" } .fa-crosshairs:before { content: "\f05b" } .fa-times-circle-o:before { content: "\f05c" } .fa-check-circle-o:before { content: "\f05d" } .fa-ban:before { content: "\f05e" } .fa-arrow-left:before { content: "\f060" } .fa-arrow-right:before { content: "\f061" } .fa-arrow-up:before { content: "\f062" } .fa-arrow-down:before { content: "\f063" } .fa-mail-forward:before, .fa-share:before { content: "\f064" } .fa-expand:before { content: "\f065" } .fa-compress:before { content: "\f066" } .fa-plus:before { content: "\f067" } .fa-minus:before { content: "\f068" } .fa-asterisk:before { content: "\f069" } .fa-exclamation-circle:before { content: "\f06a" } .fa-gift:before { content: "\f06b" } .fa-leaf:before { content: "\f06c" } .fa-fire:before { content: "\f06d" } .fa-eye:before { content: "\f06e" } .fa-eye-slash:before { content: "\f070" } .fa-exclamation-triangle:before, .fa-warning:before { content: "\f071" } .fa-plane:before { content: "\f072" } .fa-calendar:before { content: "\f073" } .fa-random:before { content: "\f074" } .fa-comment:before { content: "\f075" } .fa-magnet:before { content: "\f076" } .fa-chevron-up:before { content: "\f077" } .fa-chevron-down:before { content: "\f078" } .fa-retweet:before { content: "\f079" } .fa-shopping-cart:before { content: "\f07a" } .fa-folder:before { content: "\f07b" } .fa-folder-open:before { content: "\f07c" } .fa-arrows-v:before { content: "\f07d" } .fa-arrows-h:before { content: "\f07e" } .fa-bar-chart-o:before, .fa-bar-chart:before { content: "\f080" } .fa-twitter-square:before { content: "\f081" } .fa-facebook-square:before { content: "\f082" } .fa-camera-retro:before { content: "\f083" } .fa-key:before { content: "\f084" } .fa-cogs:before, .fa-gears:before { content: "\f085" } .fa-comments:before { content: "\f086" } .fa-thumbs-o-up:before { content: "\f087" } .fa-thumbs-o-down:before { content: "\f088" } .fa-star-half:before { content: "\f089" } .fa-heart-o:before { content: "\f08a" } .fa-sign-out:before { content: "\f08b" } .fa-linkedin-square:before { content: "\f08c" } .fa-thumb-tack:before { content: "\f08d" } .fa-external-link:before { content: "\f08e" } .fa-sign-in:before { content: "\f090" } .fa-trophy:before { content: "\f091" } .fa-github-square:before { content: "\f092" } .fa-upload:before { content: "\f093" } .fa-lemon-o:before { content: "\f094" } .fa-phone:before { content: "\f095" } .fa-square-o:before { content: "\f096" } .fa-bookmark-o:before { content: "\f097" } .fa-phone-square:before { content: "\f098" } .fa-twitter:before { content: "\f099" } .fa-facebook-f:before, .fa-facebook:before { content: "\f09a" } .fa-github:before { content: "\f09b" } .fa-unlock:before { content: "\f09c" } .fa-credit-card:before { content: "\f09d" } .fa-feed:before, .fa-rss:before { content: "\f09e" } .fa-hdd-o:before { content: "\f0a0" } .fa-bullhorn:before { content: "\f0a1" } .fa-bell:before { content: "\f0f3" } .fa-certificate:before { content: "\f0a3" } .fa-hand-o-right:before { content: "\f0a4" } .fa-hand-o-left:before { content: "\f0a5" } .fa-hand-o-up:before { content: "\f0a6" } .fa-hand-o-down:before { content: "\f0a7" } .fa-arrow-circle-left:before { content: "\f0a8" } .fa-arrow-circle-right:before { content: "\f0a9" } .fa-arrow-circle-up:before { content: "\f0aa" } .fa-arrow-circle-down:before { content: "\f0ab" } .fa-globe:before { content: "\f0ac" } .fa-wrench:before { content: "\f0ad" } .fa-tasks:before { content: "\f0ae" } .fa-filter:before { content: "\f0b0" } .fa-briefcase:before { content: "\f0b1" } .fa-arrows-alt:before { content: "\f0b2" } .fa-group:before, .fa-users:before { content: "\f0c0" } .fa-chain:before, .fa-link:before { content: "\f0c1" } .fa-cloud:before { content: "\f0c2" } .fa-flask:before { content: "\f0c3" } .fa-cut:before, .fa-scissors:before { content: "\f0c4" } .fa-copy:before, .fa-files-o:before { content: "\f0c5" } .fa-paperclip:before { content: "\f0c6" } .fa-floppy-o:before, .fa-save:before { content: "\f0c7" } .fa-square:before { content: "\f0c8" } .fa-bars:before, .fa-navicon:before, .fa-reorder:before { content: "\f0c9" } .fa-list-ul:before { content: "\f0ca" } .fa-list-ol:before { content: "\f0cb" } .fa-strikethrough:before { content: "\f0cc" } .fa-underline:before { content: "\f0cd" } .fa-table:before { content: "\f0ce" } .fa-magic:before { content: "\f0d0" } .fa-truck:before { content: "\f0d1" } .fa-pinterest:before { content: "\f0d2" } .fa-pinterest-square:before { content: "\f0d3" } .fa-google-plus-square:before { content: "\f0d4" } .fa-google-plus:before { content: "\f0d5" } .fa-money:before { content: "\f0d6" } .fa-caret-down:before { content: "\f0d7" } .fa-caret-up:before { content: "\f0d8" } .fa-caret-left:before { content: "\f0d9" } .fa-caret-right:before { content: "\f0da" } .fa-columns:before { content: "\f0db" } .fa-sort:before, .fa-unsorted:before { content: "\f0dc" } .fa-sort-desc:before, .fa-sort-down:before { content: "\f0dd" } .fa-sort-asc:before, .fa-sort-up:before { content: "\f0de" } .fa-envelope:before { content: "\f0e0" } .fa-linkedin:before { content: "\f0e1" } .fa-rotate-left:before, .fa-undo:before { content: "\f0e2" } .fa-gavel:before, .fa-legal:before { content: "\f0e3" } .fa-dashboard:before, .fa-tachometer:before { content: "\f0e4" } .fa-comment-o:before { content: "\f0e5" } .fa-comments-o:before { content: "\f0e6" } .fa-bolt:before, .fa-flash:before { content: "\f0e7" } .fa-sitemap:before { content: "\f0e8" } .fa-umbrella:before { content: "\f0e9" } .fa-clipboard:before, .fa-paste:before { content: "\f0ea" } .fa-lightbulb-o:before { content: "\f0eb" } .fa-exchange:before { content: "\f0ec" } .fa-cloud-download:before { content: "\f0ed" } .fa-cloud-upload:before { content: "\f0ee" } .fa-user-md:before { content: "\f0f0" } .fa-stethoscope:before { content: "\f0f1" } .fa-suitcase:before { content: "\f0f2" } .fa-bell-o:before { content: "\f0a2" } .fa-coffee:before { content: "\f0f4" } .fa-cutlery:before { content: "\f0f5" } .fa-file-text-o:before { content: "\f0f6" } .fa-building-o:before { content: "\f0f7" } .fa-hospital-o:before { content: "\f0f8" } .fa-ambulance:before { content: "\f0f9" } .fa-medkit:before { content: "\f0fa" } .fa-fighter-jet:before { content: "\f0fb" } .fa-beer:before { content: "\f0fc" } .fa-h-square:before { content: "\f0fd" } .fa-plus-square:before { content: "\f0fe" } .fa-angle-double-left:before { content: "\f100" } .fa-angle-double-right:before { content: "\f101" } .fa-angle-double-up:before { content: "\f102" } .fa-angle-double-down:before { content: "\f103" } .fa-angle-left:before { content: "\f104" } .fa-angle-right:before { content: "\f105" } .fa-angle-up:before { content: "\f106" } .fa-angle-down:before { content: "\f107" } .fa-desktop:before { content: "\f108" } .fa-laptop:before { content: "\f109" } .fa-tablet:before { content: "\f10a" } .fa-mobile-phone:before, .fa-mobile:before { content: "\f10b" } .fa-circle-o:before { content: "\f10c" } .fa-quote-left:before { content: "\f10d" } .fa-quote-right:before { content: "\f10e" } .fa-spinner:before { content: "\f110" } .fa-circle:before { content: "\f111" } .fa-mail-reply:before, .fa-reply:before { content: "\f112" } .fa-github-alt:before { content: "\f113" } .fa-folder-o:before { content: "\f114" } .fa-folder-open-o:before { content: "\f115" } .fa-smile-o:before { content: "\f118" } .fa-frown-o:before { content: "\f119" } .fa-meh-o:before { content: "\f11a" } .fa-gamepad:before { content: "\f11b" } .fa-keyboard-o:before { content: "\f11c" } .fa-flag-o:before { content: "\f11d" } .fa-flag-checkered:before { content: "\f11e" } .fa-terminal:before { content: "\f120" } .fa-code:before { content: "\f121" } .fa-mail-reply-all:before, .fa-reply-all:before { content: "\f122" } .fa-star-half-empty:before, .fa-star-half-full:before, .fa-star-half-o:before { content: "\f123" } .fa-location-arrow:before { content: "\f124" } .fa-crop:before { content: "\f125" } .fa-code-fork:before { content: "\f126" } .fa-chain-broken:before, .fa-unlink:before { content: "\f127" } .fa-question:before { content: "\f128" } .fa-info:before { content: "\f129" } .fa-exclamation:before { content: "\f12a" } .fa-superscript:before { content: "\f12b" } .fa-subscript:before { content: "\f12c" } .fa-eraser:before { content: "\f12d" } .fa-puzzle-piece:before { content: "\f12e" } .fa-microphone:before { content: "\f130" } .fa-microphone-slash:before { content: "\f131" } .fa-shield:before { content: "\f132" } .fa-calendar-o:before { content: "\f133" } .fa-fire-extinguisher:before { content: "\f134" } .fa-rocket:before { content: "\f135" } .fa-maxcdn:before { content: "\f136" } .fa-chevron-circle-left:before { content: "\f137" } .fa-chevron-circle-right:before { content: "\f138" } .fa-chevron-circle-up:before { content: "\f139" } .fa-chevron-circle-down:before { content: "\f13a" } .fa-html5:before { content: "\f13b" } .fa-css3:before { content: "\f13c" } .fa-anchor:before { content: "\f13d" } .fa-unlock-alt:before { content: "\f13e" } .fa-bullseye:before { content: "\f140" } .fa-ellipsis-h:before { content: "\f141" } .fa-ellipsis-v:before { content: "\f142" } .fa-rss-square:before { content: "\f143" } .fa-play-circle:before { content: "\f144" } .fa-ticket:before { content: "\f145" } .fa-minus-square:before { content: "\f146" } .fa-minus-square-o:before { content: "\f147" } .fa-level-up:before { content: "\f148" } .fa-level-down:before { content: "\f149" } .fa-check-square:before { content: "\f14a" } .fa-pencil-square:before { content: "\f14b" } .fa-external-link-square:before { content: "\f14c" } .fa-share-square:before { content: "\f14d" } .fa-compass:before { content: "\f14e" } .fa-caret-square-o-down:before, .fa-toggle-down:before { content: "\f150" } .fa-caret-square-o-up:before, .fa-toggle-up:before { content: "\f151" } .fa-caret-square-o-right:before, .fa-toggle-right:before { content: "\f152" } .fa-eur:before, .fa-euro:before { content: "\f153" } .fa-gbp:before { content: "\f154" } .fa-dollar:before, .fa-usd:before { content: "\f155" } .fa-inr:before, .fa-rupee:before { content: "\f156" } .fa-cny:before, .fa-jpy:before, .fa-rmb:before, .fa-yen:before { content: "\f157" } .fa-rouble:before, .fa-rub:before, .fa-ruble:before { content: "\f158" } .fa-krw:before, .fa-won:before { content: "\f159" } .fa-bitcoin:before, .fa-btc:before { content: "\f15a" } .fa-file:before { content: "\f15b" } .fa-file-text:before { content: "\f15c" } .fa-sort-alpha-asc:before { content: "\f15d" } .fa-sort-alpha-desc:before { content: "\f15e" } .fa-sort-amount-asc:before { content: "\f160" } .fa-sort-amount-desc:before { content: "\f161" } .fa-sort-numeric-asc:before { content: "\f162" } .fa-sort-numeric-desc:before { content: "\f163" } .fa-thumbs-up:before { content: "\f164" } .fa-thumbs-down:before { content: "\f165" } .fa-youtube-square:before { content: "\f166" } .fa-youtube:before { content: "\f167" } .fa-xing:before { content: "\f168" } .fa-xing-square:before { content: "\f169" } .fa-youtube-play:before { content: "\f16a" } .fa-dropbox:before { content: "\f16b" } .fa-stack-overflow:before { content: "\f16c" } .fa-instagram:before { content: "\f16d" } .fa-flickr:before { content: "\f16e" } .fa-adn:before { content: "\f170" } .fa-bitbucket:before { content: "\f171" } .fa-bitbucket-square:before { content: "\f172" } .fa-tumblr:before { content: "\f173" } .fa-tumblr-square:before { content: "\f174" } .fa-long-arrow-down:before { content: "\f175" } .fa-long-arrow-up:before { content: "\f176" } .fa-long-arrow-left:before { content: "\f177" } .fa-long-arrow-right:before { content: "\f178" } .fa-apple:before { content: "\f179" } .fa-windows:before { content: "\f17a" } .fa-android:before { content: "\f17b" } .fa-linux:before { content: "\f17c" } .fa-dribbble:before { content: "\f17d" } .fa-skype:before { content: "\f17e" } .fa-foursquare:before { content: "\f180" } .fa-trello:before { content: "\f181" } .fa-female:before { content: "\f182" } .fa-male:before { content: "\f183" } .fa-gittip:before, .fa-gratipay:before { content: "\f184" } .fa-sun-o:before { content: "\f185" } .fa-moon-o:before { content: "\f186" } .fa-archive:before { content: "\f187" } .fa-bug:before { content: "\f188" } .fa-vk:before { content: "\f189" } .fa-weibo:before { content: "\f18a" } .fa-renren:before { content: "\f18b" } .fa-pagelines:before { content: "\f18c" } .fa-stack-exchange:before { content: "\f18d" } .fa-arrow-circle-o-right:before { content: "\f18e" } .fa-arrow-circle-o-left:before { content: "\f190" } .fa-caret-square-o-left:before, .fa-toggle-left:before { content: "\f191" } .fa-dot-circle-o:before { content: "\f192" } .fa-wheelchair:before { content: "\f193" } .fa-vimeo-square:before { content: "\f194" } .fa-try:before, .fa-turkish-lira:before { content: "\f195" } .fa-plus-square-o:before { content: "\f196" } .fa-space-shuttle:before { content: "\f197" } .fa-slack:before { content: "\f198" } .fa-envelope-square:before { content: "\f199" } .fa-wordpress:before { content: "\f19a" } .fa-openid:before { content: "\f19b" } .fa-bank:before, .fa-institution:before, .fa-university:before { content: "\f19c" } .fa-graduation-cap:before, .fa-mortar-board:before { content: "\f19d" } .fa-yahoo:before { content: "\f19e" } .fa-google:before { content: "\f1a0" } .fa-reddit:before { content: "\f1a1" } .fa-reddit-square:before { content: "\f1a2" } .fa-stumbleupon-circle:before { content: "\f1a3" } .fa-stumbleupon:before { content: "\f1a4" } .fa-delicious:before { content: "\f1a5" } .fa-digg:before { content: "\f1a6" } .fa-pied-piper:before { content: "\f1a7" } .fa-pied-piper-alt:before { content: "\f1a8" } .fa-drupal:before { content: "\f1a9" } .fa-joomla:before { content: "\f1aa" } .fa-language:before { content: "\f1ab" } .fa-fax:before { content: "\f1ac" } .fa-building:before { content: "\f1ad" } .fa-child:before { content: "\f1ae" } .fa-paw:before { content: "\f1b0" } .fa-spoon:before { content: "\f1b1" } .fa-cube:before { content: "\f1b2" } .fa-cubes:before { content: "\f1b3" } .fa-behance:before { content: "\f1b4" } .fa-behance-square:before { content: "\f1b5" } .fa-steam:before { content: "\f1b6" } .fa-steam-square:before { content: "\f1b7" } .fa-recycle:before { content: "\f1b8" } .fa-automobile:before, .fa-car:before { content: "\f1b9" } .fa-cab:before, .fa-taxi:before { content: "\f1ba" } .fa-tree:before { content: "\f1bb" } .fa-spotify:before { content: "\f1bc" } .fa-deviantart:before { content: "\f1bd" } .fa-soundcloud:before { content: "\f1be" } .fa-database:before { content: "\f1c0" } .fa-file-pdf-o:before { content: "\f1c1" } .fa-file-word-o:before { content: "\f1c2" } .fa-file-excel-o:before { content: "\f1c3" } .fa-file-powerpoint-o:before { content: "\f1c4" } .fa-file-image-o:before, .fa-file-photo-o:before, .fa-file-picture-o:before { content: "\f1c5" } .fa-file-archive-o:before, .fa-file-zip-o:before { content: "\f1c6" } .fa-file-audio-o:before, .fa-file-sound-o:before { content: "\f1c7" } .fa-file-movie-o:before, .fa-file-video-o:before { content: "\f1c8" } .fa-file-code-o:before { content: "\f1c9" } .fa-vine:before { content: "\f1ca" } .fa-codepen:before { content: "\f1cb" } .fa-jsfiddle:before { content: "\f1cc" } .fa-life-bouy:before, .fa-life-buoy:before, .fa-life-ring:before, .fa-life-saver:before, .fa-support:before { content: "\f1cd" } .fa-circle-o-notch:before { content: "\f1ce" } .fa-ra:before, .fa-rebel:before { content: "\f1d0" } .fa-empire:before, .fa-ge:before { content: "\f1d1" } .fa-git-square:before { content: "\f1d2" } .fa-git:before { content: "\f1d3" } .fa-hacker-news:before, .fa-y-combinator-square:before, .fa-yc-square:before { content: "\f1d4" } .fa-tencent-weibo:before { content: "\f1d5" } .fa-qq:before { content: "\f1d6" } .fa-wechat:before, .fa-weixin:before { content: "\f1d7" } .fa-paper-plane:before, .fa-send:before { content: "\f1d8" } .fa-paper-plane-o:before, .fa-send-o:before { content: "\f1d9" } .fa-history:before { content: "\f1da" } .fa-circle-thin:before { content: "\f1db" } .fa-header:before { content: "\f1dc" } .fa-paragraph:before { content: "\f1dd" } .fa-sliders:before { content: "\f1de" } .fa-share-alt:before { content: "\f1e0" } .fa-share-alt-square:before { content: "\f1e1" } .fa-bomb:before { content: "\f1e2" } .fa-futbol-o:before, .fa-soccer-ball-o:before { content: "\f1e3" } .fa-tty:before { content: "\f1e4" } .fa-binoculars:before { content: "\f1e5" } .fa-plug:before { content: "\f1e6" } .fa-slideshare:before { content: "\f1e7" } .fa-twitch:before { content: "\f1e8" } .fa-yelp:before { content: "\f1e9" } .fa-newspaper-o:before { content: "\f1ea" } .fa-wifi:before { content: "\f1eb" } .fa-calculator:before { content: "\f1ec" } .fa-paypal:before { content: "\f1ed" } .fa-google-wallet:before { content: "\f1ee" } .fa-cc-visa:before { content: "\f1f0" } .fa-cc-mastercard:before { content: "\f1f1" } .fa-cc-discover:before { content: "\f1f2" } .fa-cc-amex:before { content: "\f1f3" } .fa-cc-paypal:before { content: "\f1f4" } .fa-cc-stripe:before { content: "\f1f5" } .fa-bell-slash:before { content: "\f1f6" } .fa-bell-slash-o:before { content: "\f1f7" } .fa-trash:before { content: "\f1f8" } .fa-copyright:before { content: "\f1f9" } .fa-at:before { content: "\f1fa" } .fa-eyedropper:before { content: "\f1fb" } .fa-paint-brush:before { content: "\f1fc" } .fa-birthday-cake:before { content: "\f1fd" } .fa-area-chart:before { content: "\f1fe" } .fa-pie-chart:before { content: "\f200" } .fa-line-chart:before { content: "\f201" } .fa-lastfm:before { content: "\f202" } .fa-lastfm-square:before { content: "\f203" } .fa-toggle-off:before { content: "\f204" } .fa-toggle-on:before { content: "\f205" } .fa-bicycle:before { content: "\f206" } .fa-bus:before { content: "\f207" } .fa-ioxhost:before { content: "\f208" } .fa-angellist:before { content: "\f209" } .fa-cc:before { content: "\f20a" } .fa-ils:before, .fa-shekel:before, .fa-sheqel:before { content: "\f20b" } .fa-meanpath:before { content: "\f20c" } .fa-buysellads:before { content: "\f20d" } .fa-connectdevelop:before { content: "\f20e" } .fa-dashcube:before { content: "\f210" } .fa-forumbee:before { content: "\f211" } .fa-leanpub:before { content: "\f212" } .fa-sellsy:before { content: "\f213" } .fa-shirtsinbulk:before { content: "\f214" } .fa-simplybuilt:before { content: "\f215" } .fa-skyatlas:before { content: "\f216" } .fa-cart-plus:before { content: "\f217" } .fa-cart-arrow-down:before { content: "\f218" } .fa-diamond:before { content: "\f219" } .fa-ship:before { content: "\f21a" } .fa-user-secret:before { content: "\f21b" } .fa-motorcycle:before { content: "\f21c" } .fa-street-view:before { content: "\f21d" } .fa-heartbeat:before { content: "\f21e" } .fa-venus:before { content: "\f221" } .fa-mars:before { content: "\f222" } .fa-mercury:before { content: "\f223" } .fa-intersex:before, .fa-transgender:before { content: "\f224" } .fa-transgender-alt:before { content: "\f225" } .fa-venus-double:before { content: "\f226" } .fa-mars-double:before { content: "\f227" } .fa-venus-mars:before { content: "\f228" } .fa-mars-stroke:before { content: "\f229" } .fa-mars-stroke-v:before { content: "\f22a" } .fa-mars-stroke-h:before { content: "\f22b" } .fa-neuter:before { content: "\f22c" } .fa-genderless:before { content: "\f22d" } .fa-facebook-official:before { content: "\f230" } .fa-pinterest-p:before { content: "\f231" } .fa-whatsapp:before { content: "\f232" } .fa-server:before { content: "\f233" } .fa-user-plus:before { content: "\f234" } .fa-user-times:before { content: "\f235" } .fa-bed:before, .fa-hotel:before { content: "\f236" } .fa-viacoin:before { content: "\f237" } .fa-train:before { content: "\f238" } .fa-subway:before { content: "\f239" } .fa-medium:before { content: "\f23a" } .fa-y-combinator:before, .fa-yc:before { content: "\f23b" } .fa-optin-monster:before { content: "\f23c" } .fa-opencart:before { content: "\f23d" } .fa-expeditedssl:before { content: "\f23e" } .fa-battery-4:before, .fa-battery-full:before { content: "\f240" } .fa-battery-3:before, .fa-battery-three-quarters:before { content: "\f241" } .fa-battery-2:before, .fa-battery-half:before { content: "\f242" } .fa-battery-1:before, .fa-battery-quarter:before { content: "\f243" } .fa-battery-0:before, .fa-battery-empty:before { content: "\f244" } .fa-mouse-pointer:before { content: "\f245" } .fa-i-cursor:before { content: "\f246" } .fa-object-group:before { content: "\f247" } .fa-object-ungroup:before { content: "\f248" } .fa-sticky-note:before { content: "\f249" } .fa-sticky-note-o:before { content: "\f24a" } .fa-cc-jcb:before { content: "\f24b" } .fa-cc-diners-club:before { content: "\f24c" } .fa-clone:before { content: "\f24d" } .fa-balance-scale:before { content: "\f24e" } .fa-hourglass-o:before { content: "\f250" } .fa-hourglass-1:before, .fa-hourglass-start:before { content: "\f251" } .fa-hourglass-2:before, .fa-hourglass-half:before { content: "\f252" } .fa-hourglass-3:before, .fa-hourglass-end:before { content: "\f253" } .fa-hourglass:before { content: "\f254" } .fa-hand-grab-o:before, .fa-hand-rock-o:before { content: "\f255" } .fa-hand-paper-o:before, .fa-hand-stop-o:before { content: "\f256" } .fa-hand-scissors-o:before { content: "\f257" } .fa-hand-lizard-o:before { content: "\f258" } .fa-hand-spock-o:before { content: "\f259" } .fa-hand-pointer-o:before { content: "\f25a" } .fa-hand-peace-o:before { content: "\f25b" } .fa-trademark:before { content: "\f25c" } .fa-registered:before { content: "\f25d" } .fa-creative-commons:before { content: "\f25e" } .fa-gg:before { content: "\f260" } .fa-gg-circle:before { content: "\f261" } .fa-tripadvisor:before { content: "\f262" } .fa-odnoklassniki:before { content: "\f263" } .fa-odnoklassniki-square:before { content: "\f264" } .fa-get-pocket:before { content: "\f265" } .fa-wikipedia-w:before { content: "\f266" } .fa-safari:before { content: "\f267" } .fa-chrome:before { content: "\f268" } .fa-firefox:before { content: "\f269" } .fa-opera:before { content: "\f26a" } .fa-internet-explorer:before { content: "\f26b" } .fa-television:before, .fa-tv:before { content: "\f26c" } .fa-contao:before { content: "\f26d" } .fa-500px:before { content: "\f26e" } .fa-amazon:before { content: "\f270" } .fa-calendar-plus-o:before { content: "\f271" } .fa-calendar-minus-o:before { content: "\f272" } .fa-calendar-times-o:before { content: "\f273" } .fa-calendar-check-o:before { content: "\f274" } .fa-industry:before { content: "\f275" } .fa-map-pin:before { content: "\f276" } .fa-map-signs:before { content: "\f277" } .fa-map-o:before { content: "\f278" } .fa-map:before { content: "\f279" } .fa-commenting:before { content: "\f27a" } .fa-commenting-o:before { content: "\f27b" } .fa-houzz:before { content: "\f27c" } .fa-vimeo:before { content: "\f27d" } .fa-black-tie:before { content: "\f27e" } .fa-fonticons:before { content: "\f280" } .fa-reddit-alien:before { content: "\f281" } .fa-edge:before { content: "\f282" } .fa-credit-card-alt:before { content: "\f283" } .fa-codiepie:before { content: "\f284" } .fa-modx:before { content: "\f285" } .fa-fort-awesome:before { content: "\f286" } .fa-usb:before { content: "\f287" } .fa-product-hunt:before { content: "\f288" } .fa-mixcloud:before { content: "\f289" } .fa-scribd:before { content: "\f28a" } .fa-pause-circle:before { content: "\f28b" } .fa-pause-circle-o:before { content: "\f28c" } .fa-stop-circle:before { content: "\f28d" } .fa-stop-circle-o:before { content: "\f28e" } .fa-shopping-bag:before { content: "\f290" } .fa-shopping-basket:before { content: "\f291" } .fa-hashtag:before { content: "\f292" } .fa-bluetooth:before { content: "\f293" } .fa-bluetooth-b:before { content: "\f294" } .fa-percent:before { content: "\f295" } .sttabs { position: relative; overflow: hidden; margin: 0 auto; width: 100%; font-weight: 300 } .sticon::before { display: inline-block; margin: 0 .4em 0 0; vertical-align: middle; font-size: 20px; speak: none; -webkit-backface-visibility: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale } .sttabs nav { text-align: center } .sttabs nav ul { position: relative; display: -ms-flexbox; display: -webkit-flex; display: -moz-flex; display: -ms-flex; display: flex; margin: 0 auto; padding: 0; font-family: Poppins, sans-serif; list-style: none; -ms-box-orient: horizontal; -ms-box-pack: center; -webkit-flex-flow: row wrap; -moz-flex-flow: row wrap; -ms-flex-flow: row wrap; flex-flow: row wrap; -webkit-justify-content: center; -moz-justify-content: center; -ms-justify-content: center; justify-content: center } .sttabs nav ul li { position: relative; z-index: 1; display: block; margin: 0; text-align: center; -webkit-flex: 1; -moz-flex: 1; -ms-flex: 1; flex: 1 } .sttabs nav a { position: relative; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 2.5 } .sttabs nav a span { vertical-align: middle; font-wight: 500; font-size: 14px; font-family: Rubik, sans-serif } .sttabs nav a:focus { outline: 0 } .sttabs nav li.tab-current a { color: #f33155 } .content-wrap { background: #fff } .tabs-style-bar nav ul li a { margin: 0 2px; background-color: #f7fafc; color: #686868; padding: 5px 0; transition: background-color .2s, color .2s } .tabs-style-bar nav ul li a:focus, .tabs-style-bar nav ul li a:hover { color: #f33155 } .tabs-style-bar nav ul li a span { text-transform: uppercase; letter-spacing: 1px; font-size: 14px; font-family: Poppins, sans-serif } .tabs-style-bar nav ul li.tab-current a { background: #fb9678; color: #fff } .tabs-style-iconbox nav { background: #f7fafc } .tabs-style-iconbox nav ul li a { overflow: visible; padding: 25px 0; line-height: 1; -webkit-transition: color .2s; transition: color .2s; color: #263238 } .tabs-style-iconbox nav ul li.tab-current { z-index: 1 } .tabs-style-iconbox nav ul li.tab-current a { background: #41b3f9; color: #fff; box-shadow: -1px 0 0 #fff } .tabs-style-iconbox nav ul li.tab-current a::after { position: absolute; top: 100%; left: 50%; margin-left: -10px; width: 0; height: 0; border: solid transparent; border-width: 10px; border-top-color: #41b3f9; content: ''; pointer-events: none } .tabs-style-iconbox nav ul li::after, .tabs-style-iconbox nav ul li:first-child::before { position: absolute; top: 20%; right: 0; z-index: -1; width: 1px; height: 60%; content: '' } .tabs-style-iconbox nav ul li:first-child::before { right: auto; left: 0 } .tabs-style-iconbox .sticon::before { display: block; margin: 0 0 .25em } .tabs-style-underline nav { border: 1px solid rgba(120, 130, 140, .13) } .tabs-style-underline nav a { padding: 20px 0; border-left: 1px solid rgba(120, 130, 140, .13); -webkit-transition: color .2s; transition: color .2s; color: #263238 } .tabs-style-underline nav li:last-child a { border-right: 1px solid rgba(120, 130, 140, .13) } .tabs-style-underline nav li a::after { position: absolute; bottom: 0; left: 0; width: 100%; height: 6px; background: #fb9678; content: ''; -webkit-transition: -webkit-transform .3s; transition: transform .3s; -webkit-transform: translate3d(0, 150%, 0); transform: translate3d(0, 150%, 0) } .tabs-style-underline nav li.tab-current a::after { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } .tabs-style-linetriangle nav a { overflow: visible; border-bottom: 1px solid rgba(0, 0, 0, .2); -webkit-transition: color .2s; transition: color .2s } .tabs-style-linetriangle nav a span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; padding: 15px 0; color: #263238 } .tabs-style-linetriangle nav li.tab-current a:after, .tabs-style-linetriangle nav li.tab-current a:before { position: absolute; top: 100%; left: 50%; width: 0; height: 0; border: solid transparent; content: ''; pointer-events: none } .tabs-style-linetriangle nav li.tab-current a:after { margin-left: -10px; border-width: 10px; border-top-color: #fff } .tabs-style-linetriangle nav li.tab-current a span { color: #f33155 } .tabs-style-linetriangle nav li.tab-current a:before { margin-left: -11px; border-width: 11px; border-top-color: rgba(0, 0, 0, .2) } .tabs-style-iconfall { overflow: visible } .tabs-style-iconfall nav { max-width: 1200px; margin: 0 auto } .tabs-style-iconfall nav a { display: inline-block; overflow: visible; padding: 1em 0 2em; color: #263238; line-height: 1; -webkit-transition: color .3s cubic-bezier(.7, 0, .3, 1); transition: color .3s cubic-bezier(.7, 0, .3, 1) } .tabs-style-iconfall nav a:focus, .tabs-style-iconfall nav a:hover, .tabs-style-iconfall nav li.tab-current a { color: #f33155 } .tabs-style-iconfall nav li::before { position: absolute; bottom: 1em; left: 50%; margin-left: -20px; width: 40px; height: 4px; background: #f33155; content: ''; opacity: 0; -webkit-transition: -webkit-transform .2s ease-in; transition: transform .2s ease-in; -webkit-transform: scale3d(0, 1, 1); transform: scale3d(0, 1, 1) } .tabs-style-iconfall nav li.tab-current::before { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1) } .tabs-style-iconfall nav li.tab-current .sticon::before { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } .tabs-style-iconfall .sticon::before { display: block; margin: 0 0 .35em; opacity: 0; font-size: 24px; -webkit-transition: -webkit-transform .2s, opacity .2s; transition: transform .2s, opacity .2s; -webkit-transform: translate3d(0, -100px, 0); transform: translate3d(0, -100px, 0); pointer-events: none } @media screen and (max-width: 58em) { .tabs-style-iconfall nav li .sticon::before { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } } .tabs-style-linemove nav { background: #f7fafc } .tabs-style-linemove nav li:last-child::before { position: absolute; bottom: 0; left: 0; width: 100%; height: 4px; background: #f33155; content: ''; -webkit-transition: -webkit-transform .3s; transition: transform .3s } .tabs-style-linemove nav li:first-child.tab-current~li:last-child::before { -webkit-transform: translate3d(-400%, 0, 0); transform: translate3d(-400%, 0, 0) } .tabs-style-linemove nav li:nth-child(2).tab-current~li:last-child::before { -webkit-transform: translate3d(-300%, 0, 0); transform: translate3d(-300%, 0, 0) } .tabs-style-linemove nav li:nth-child(3).tab-current~li:last-child::before { -webkit-transform: translate3d(-200%, 0, 0); transform: translate3d(-200%, 0, 0) } .tabs-style-linemove nav li:nth-child(4).tab-current~li:last-child::before { -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0) } .tabs-style-linemove nav a { padding: 30px 0; color: #263238; line-height: 1; -webkit-transition: color .3s, -webkit-transform .3s; transition: color .3s, transform .3s } .tabs-style-linemove nav li.tab-current a { color: #f33155 } .tabs-style-line nav a { padding: 20px 10px; box-shadow: inset 0 -2px #d1d3d2; color: #686868; text-align: left; text-transform: uppercase; letter-spacing: 1px; line-height: 1; -webkit-transition: color .3s, box-shadow .3s; transition: color .3s, box-shadow .3s } .tabs-style-line nav a:focus, .tabs-style-line nav a:hover { box-shadow: inset 0 -2px #74777b } .tabs-style-line nav li.tab-current a { box-shadow: inset 0 -2px #f33155; color: #f33155 } @media screen and (max-width: 58em) { .tabs-style-line nav ul { display: block; box-shadow: none } .tabs-style-line nav ul li { display: block; -webkit-flex: none; flex: none } } .tabs-style-circle { overflow: visible } .tabs-style-circle nav li { margin-top: 60px!important; margin-bottom: 60px!important } .tabs-style-circle nav li::before { position: absolute; top: 50%; left: 50%; margin: -60px 0 0 -60px; width: 120px; height: 120px; border: 1px solid #fb9678; border-radius: 50%; content: ''; opacity: 0; -webkit-transition: -webkit-transform .2s, opacity .2s; transition: transform .2s, opacity .2s; -webkit-transition-timing-function: cubic-bezier(.7, 0, .3, 1); transition-timing-function: cubic-bezier(.7, 0, .3, 1) } .tabs-style-circle nav a { overflow: visible; color: #2b2b2b; font-weight: 500; font-size: 14; line-height: 1.1; -webkit-transition: color .3s cubic-bezier(.7, 0, .3, 1); transition: color .3s cubic-bezier(.7, 0, .3, 1) } .tabs-style-circle nav a span { display: inline-block } .tabs-style-circle nav a:focus, .tabs-style-circle nav a:hover, .tabs-style-circle nav li.tab-current a { color: #f33155 } .tabs-style-circle nav li.tab-current a span { -webkit-transform: translate3d(0, 4px, 0); transform: translate3d(0, 4px, 0) } @media screen and (max-width: 58em) { .tabs-style-circle nav li::before { margin: -40px 0 0 -40px; width: 80px; height: 80px } } .tabs-style-circle nav li.tab-current::before { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1) } .tabs-style-circle .icon::before, .tabs-style-circle nav a span { -webkit-transition: -webkit-transform .3s cubic-bezier(.7, 0, .3, 1); transition: transform .3s cubic-bezier(.7, 0, .3, 1) } .tabs-style-circle .sticon::before { display: block; margin: 0; pointer-events: none } .tabs-style-circle nav li.tab-current .sticon::before { -webkit-transform: translate3d(0, -4px, 0); transform: translate3d(0, -4px, 0) } .tabs-style-shape { max-width: 1200px; margin: 0 auto } .tabs-style-shape nav ul li { margin: 0 3em } .tabs-style-shape nav ul li:first-child { margin-left: 0 } .tabs-style-shape nav ul li.tab-current { z-index: 1 } .tabs-style-shape nav li a { overflow: visible; margin: 0 -3em 0 0; padding: 0; color: #fff; font-weight: 500 } .tabs-style-shape nav li a svg { position: absolute; left: 100%; margin: 0; width: 3em; height: 100%; fill: #bdc2c9 } .tabs-style-shape nav li:first-child a span { padding-left: 2em; border-radius: 30px 0 0 } .tabs-style-shape nav li:last-child a span { padding-right: 2em; border-radius: 0 30px 0 0 } .tabs-style-shape nav li a svg:nth-child(2), .tabs-style-shape nav li:last-child a svg { right: 100%; left: auto; -webkit-transform: scale3d(-1, 1, 1); transform: scale3d(-1, 1, 1) } .tabs-style-shape nav li a span { display: block; overflow: hidden; padding: .65em 0; background-color: #bdc2c9; text-overflow: ellipsis; white-space: nowrap } .tabs-style-shape nav li a:hover span { background-color: #f33155 } .tabs-style-shape nav li a:hover svg { fill: #f33155 } .tabs-style-shape nav li a svg { pointer-events: none } .tabs-style-shape nav li a svg use { pointer-events: auto } .tabs-style-shape nav li.tab-current a span, .tabs-style-shape nav li.tab-current a svg { -webkit-transition: none; transition: none } .tabs-style-shape nav li.tab-current a span { background: #f7fafc } .tabs-style-shape nav li.tab-current a svg { fill: #f7fafc } .tabs-style-shape .content-wrap { background: #f7fafc } @media screen and (max-width: 58em) { .tabs-style-shape nav ul { display: block; padding-top: 1.5em } .tabs-style-shape nav ul li { display: block; margin: -1.25em 0 0; -webkit-flex: none; flex: none } .tabs-style-shape nav ul li a { margin: 0 } .tabs-style-shape nav ul li svg { display: none } .tabs-style-shape nav ul li a span { padding: 1.25em 0 2em!important; border-radius: 30px 30px 0 0!important; box-shadow: 0 -1px 2px rgba(0, 0, 0, .1); line-height: 1 } .tabs-style-shape nav ul li:last-child a span { padding: 1.25em 0!important } .tabs-style-shape nav ul li.tab-current { z-index: 1 } } .tabs-style-linebox nav ul li { margin: 0 .5em; -webkit-flex: none; flex: none } .tabs-style-linebox nav a { padding: 0 1.5em; color: #263238; font-weight: 500; -webkit-transition: color .3s; transition: color .3s } .tabs-style-linebox nav a:focus, .tabs-style-linebox nav a:hover { color: #f33155 } .tabs-style-linebox nav li.tab-current a { color: #fff } .tabs-style-linebox nav a::after { position: absolute; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; background: #d2d8d6; content: ''; -webkit-transition: background-color .3s, -webkit-transform .3s; transition: background-color .3s, transform .3s; -webkit-transition-timing-function: ease, cubic-bezier(.7, 0, .3, 1); transition-timing-function: ease, cubic-bezier(.7, 0, .3, 1); -webkit-transform: translate3d(0, 100%, 0) translate3d(0, -3px, 0); transform: translate3d(0, 100%, 0) translate3d(0, -3px, 0) } .tabs-style-linebox nav li.tab-current a::after { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } .tabs-style-linebox nav a:focus::after, .tabs-style-linebox nav a:hover::after, .tabs-style-linebox nav li.tab-current a::after { background: #f33155 } @media screen and (max-width: 58em) { .tabs-style-linebox nav ul { display: block; box-shadow: none } .tabs-style-linebox nav ul li { display: block; -webkit-flex: none; flex: none } } .tabs-style-flip { max-width: 1200px; margin: 0 auto } .tabs-style-flip nav a { padding: .5em 0; color: #263238; -webkit-transition: color .3s; transition: color .3s } .tabs-style-flip nav a:focus, .tabs-style-flip nav a:hover { color: #f33155 } .tabs-style-flip nav a span { text-transform: uppercase; letter-spacing: 1px } .tabs-style-flip nav a::after { position: absolute; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; background-color: #f0f0f0; content: ''; -webkit-transition: -webkit-transform .3s, background-color .3s; transition: transform .3s, background-color .3s; -webkit-transform: perspective(900px) rotate3d(1, 0, 0, 90deg); transform: perspective(900px) rotate3d(1, 0, 0, 90deg); -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-perspective-origin: 50% 100%; perspective-origin: 50% 100% } .tabs-style-flip nav li.tab-current a { color: #f33155 } .tabs-style-flip nav li.tab-current a::after { background-color: #f7fafc; -webkit-transform: perspective(900px) rotate3d(1, 0, 0, 0deg); transform: perspective(900px) rotate3d(1, 0, 0, 0deg) } .tabs-style-flip .content-wrap { background: #f7fafc } .tabs-style-circlefill { max-width: 800px; border: 1px solid #f33155; margin: 0 auto } .tabs-style-circlefill nav ul li { overflow: hidden; border-right: 1px solid #f33155 } .tabs-style-circlefill nav li a { padding: 1.5em 0; color: #fff; font-size: 1.25em } .tabs-style-circlefill nav li:first-child { border-left: none } .tabs-style-circlefill nav li:last-child { border: none } .tabs-style-circlefill nav li::before { position: absolute; top: 50%; left: 50%; margin: -40px 0 0 -40px; width: 80px; height: 80px; border: 1px solid #f33155; border-radius: 50%; background: #f33155; content: ''; -webkit-transition: -webkit-transform .3s; transition: transform .3s } .tabs-style-circlefill nav li.tab-current::before { -webkit-transform: scale3d(2.5, 2.5, 1); transform: scale3d(2.5, 2.5, 1) } .tabs-style-circlefill nav a { -webkit-transition: color .3s; transition: color .3s } .tabs-style-circlefill nav a span { display: none } .tabs-style-circlefill nav li.tab-current a { color: #fff } .tabs-style-circlefill .icon::before { display: block; margin: 0; pointer-events: none } .tabs-style-circlefill .content-wrap { border-top: 1px solid #f33155 } .content-wrap { position: relative } .content-wrap section { display: none; margin: 0 auto; padding: 25px; min-height: 150px } .content-wrap section p { margin: 0; padding: .75em 0 } .content-wrap section.content-current { display: block } .no-js .content-wrap section { display: block; padding-bottom: 2em; border-bottom: 1px solid rgba(255, 255, 255, .6) } .no-flexbox nav ul { display: block } .no-flexbox nav ul li { min-width: 15%; display: inline-block } @media screen and (max-width: 58em) { .sttabs nav a span { display: none } .sttabs nav a:before { margin-right: 0 } } .mytooltip { display: inline; position: relative; z-index: 9999 } .tooltip-item { background: rgba(0, 0, 0, .1); cursor: pointer; display: inline-block; font-weight: 500; padding: 0 10px } .tooltip-item::after { content: ''; position: absolute; width: 360px; height: 20px; bottom: 100%; left: 50%; pointer-events: none; -webkit-transform: translateX(-50%); transform: translateX(-50%) } .mytooltip:hover .tooltip-item::after { pointer-events: auto } .tooltip-content { position: absolute; z-index: 9999; width: 360px; left: 50%; margin: 0 0 20px -180px; bottom: 100%; text-align: left; font-size: 14px; line-height: 30px; box-shadow: -5px -5px 15px rgba(48, 54, 61, .2); background: #2b2b2b; opacity: 0; cursor: default; pointer-events: none } .tooltip-effect-1 .tooltip-content { -webkit-transform: translate3d(0, -10px, 0); transform: translate3d(0, -10px, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s; color: #fff } .tooltip-effect-2 .tooltip-content { -webkit-transform-origin: 50% calc(110%); transform-origin: 50% calc(110%); -webkit-transform: perspective(1000px) rotate3d(1, 0, 0, 45deg); transform: perspective(1000px) rotate3d(1, 0, 0, 45deg); -webkit-transition: opacity .2s, -webkit-transform .2s; transition: opacity .2s, transform .2s } .tooltip-effect-3 .tooltip-content { -webkit-transform: translate3d(0, 10px, 0) rotate3d(1, 1, 0, 25deg); transform: translate3d(0, 10px, 0) rotate3d(1, 1, 0, 25deg); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-4 .tooltip-content { -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-transform: scale3d(.7, .3, 1); transform: scale3d(.7, .3, 1); -webkit-transition: opacity .2s, -webkit-transform .2s; transition: opacity .2s, transform .2s } .tooltip-effect-5 .tooltip-content { width: 180px; margin-left: -90px; -webkit-transform-origin: 50% calc(106%); transform-origin: 50% calc(106%); -webkit-transform: rotate3d(0, 0, 1, 15deg); transform: rotate3d(0, 0, 1, 15deg); -webkit-transition: opacity .2s, -webkit-transform .2s; transition: opacity .2s, transform .2s; -webkit-transition-timing-function: ease, cubic-bezier(.17, .67, .4, 1.39); transition-timing-function: ease, cubic-bezier(.17, .67, .4, 1.39) } .mytooltip:hover .tooltip-content { pointer-events: auto; opacity: 1; -webkit-transform: translate3d(0, 0, 0) rotate3d(0, 0, 0, 0); transform: translate3d(0, 0, 0) rotate3d(0, 0, 0, 0) } .tooltip.tooltip-effect-2:hover .tooltip-content { -webkit-transform: perspective(1000px) rotate3d(1, 0, 0, 0deg); transform: perspective(1000px) rotate3d(1, 0, 0, 0deg) } .tooltip-content::after { content: ''; top: 100%; left: 50%; border: solid transparent; height: 0; width: 0; position: absolute; pointer-events: none; border-color: #2a3035 transparent transparent; border-width: 10px; margin-left: -10px } .tooltip-content img { position: relative; height: 140px; display: block; float: left; margin-right: 1em } .tooltip-text { font-size: 14px; line-height: 24px; display: block; padding: 1.31em 1.21em 1.21em 0; color: #fff } .tooltip-effect-5 .tooltip-text { padding: 1.4em } a.mytooltip { font-weight: 500; color: #fb9678 } .tooltip-content2 { position: absolute; z-index: 9999; width: 80px; height: 80px; padding-top: 25px; left: 50%; margin-left: -40px; bottom: 100%; border-radius: 50%; text-align: center; background: #fb9678; color: #fff; opacity: 0; margin-bottom: 20px; cursor: default; pointer-events: none } .tooltip-content2 i { opacity: 0 } .mytooltip:hover .tooltip-content2, .mytooltip:hover .tooltip-content2 i { opacity: 1; font-size: 18px } .tooltip-effect-6 .tooltip-content2 { -webkit-transform: translate3d(0, 10px, 0) rotate3d(1, 1, 1, 45deg); transform: translate3d(0, 10px, 0) rotate3d(1, 1, 1, 45deg); -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-6 .tooltip-content2 i { -webkit-transform: scale3d(0, 0, 1); transform: scale3d(0, 0, 1); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-7 .tooltip-content2 { -webkit-transform: translate3d(0, 10px, 0); transform: translate3d(0, 10px, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-7 .tooltip-content2 i { -webkit-transform: translate3d(0, 15px, 0); transform: translate3d(0, 15px, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-8 .tooltip-content2 { -webkit-transform: translate3d(0, 10px, 0) rotate3d(0, 1, 0, 90deg); transform: translate3d(0, 10px, 0) rotate3d(0, 1, 0, 90deg); -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-8 .tooltip-content2 i { -webkit-transform: scale3d(0, 0, 1); transform: scale3d(0, 0, 1); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-9 .tooltip-content2 { -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-effect-9 .tooltip-content2 i { -webkit-transform: translate3d(0, 20px, 0); transform: translate3d(0, 20px, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .mytooltip:hover .tooltip-content2, .mytooltip:hover .tooltip-content2 i { pointer-events: auto; -webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1); transform: translate3d(0, 0, 0) scale3d(1, 1, 1) } .tooltip-effect-6:hover .tooltip-content2 i { -webkit-transform: rotate3d(1, 1, 1, 0); transform: rotate3d(1, 1, 1, 0) } .tooltip-content2::after { content: ''; position: absolute; top: 100%; left: 50%; margin: -7px 0 0 -15px; width: 30px; height: 20px; /*background: url(../../plugins/images/tooltip/tooltip1.svg) center center no-repeat;*/ background-size: 100% } .tooltip-content3 { position: absolute; /*background: url(../../plugins/images/tooltip/shape1.svg) center bottom no-repeat;*/ background-size: 100% 100%; z-index: 9999; width: 200px; bottom: 100%; left: 50%; margin-left: -100px; padding: 50px 30px; text-align: center; color: #fff; opacity: 0; cursor: default; font-size: 14; line-height: 27px; pointer-events: none; -webkit-transform: scale3d(.1, .2, 1); transform: scale3d(.1, .2, 1); -webkit-transform-origin: 50% 120%; transform-origin: 50% 120%; -webkit-transition: opacity .4s, -webkit-transform .4s; transition: opacity .4s, transform .4s; -webkit-transition-timing-function: ease, cubic-bezier(.6, 0, .4, 1); transition-timing-function: ease, cubic-bezier(.6, 0, .4, 1) } .mytooltip:hover .tooltip-content3 { opacity: 1; pointer-events: auto; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1) } .tooltip-content3::after { content: ''; position: absolute; width: 16px; height: 16px; left: 50%; margin-left: -8px; top: 100%; background: #00AEEF; -webkit-transform: translate3d(0, -60%, 0) rotate3d(0, 0, 1, 45deg); transform: translate3d(0, -60%, 0) rotate3d(0, 0, 1, 45deg) } .tooltip-item2 { color: #03a9f3; cursor: pointer; z-index: 100; position: relative; display: inline-block; font-weight: 500; -webkit-transition: background-color .3s, color .3s, -webkit-transform .3s; transition: background-color .3s, color .3s, transform .3s } .mytooltip:hover .tooltip-item2 { color: #fff; -webkit-transform: translate3d(0, -.5em, 0); transform: translate3d(0, -.5em, 0) } .tooltip-content4 { position: absolute; z-index: 99; width: 360px; left: 50%; margin-left: -180px; bottom: -5px; text-align: left; background: #03a9f3; opacity: 0; font-size: 14px; line-height: 27px; padding: 1.5em; color: #fff; border-bottom: 55px solid #2b2b2b; cursor: default; pointer-events: none; border-radius: 5px; -webkit-transform: translate3d(0, -.5em, 0); transform: translate3d(0, -.5em, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .tooltip-content4 a { color: #2b2b2b } .tooltip-text2 { opacity: 0; -webkit-transform: translate3d(0, 1.5em, 0); transform: translate3d(0, 1.5em, 0); -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s } .mytooltip:hover .tooltip-content4, .mytooltip:hover .tooltip-text2 { pointer-events: auto; opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } .tooltip-content5 { position: absolute; z-index: 9999; width: 300px; left: 50%; bottom: 100%; font-size: 20px; line-height: 1.4; text-align: center; font-weight: 400; color: #fff; background: 0 0; opacity: 0; margin: 0 0 20px -150px; cursor: default; pointer-events: none; -webkit-font-smoothing: antialiased; -webkit-transition: opacity .3s .3s; transition: opacity .3s .3s } .mytooltip:hover .tooltip-content5 { opacity: 1; pointer-events: auto; -webkit-transition-delay: 0s; transition-delay: 0s } .tooltip-content5 span { display: block } .tooltip-text3 { border-bottom: 10px solid #fb9678; overflow: hidden; -webkit-transform: scale3d(0, 1, 1); transform: scale3d(0, 1, 1); -webkit-transition: -webkit-transform .3s .3s; transition: transform .3s .3s } .mytooltip:hover .tooltip-text3 { -webkit-transition-delay: 0s; transition-delay: 0s; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1) } .tooltip-inner2 { background: #2b2b2b; padding: 40px; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); webkit-transition: -webkit-transform .3s; transition: transform .3s } .mytooltip:hover .tooltip-inner2 { -webkit-transition-delay: .3s; transition-delay: .3s; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0) } .tooltip-content5::after { content: ''; bottom: -20px; left: 50%; border: solid transparent; height: 0; width: 0; position: absolute; pointer-events: none; border-color: #fb9678 transparent transparent; border-width: 10px; margin-left: -10px } @media (max-width: 1350px) { .carousel .item h3 { font-size: 17px; height: 90px } .inbox-center a { width: 400px } } .search-listing { padding: 0; margin: 0 } .search-listing li { list-style: none; padding: 15px 0; border-bottom: 1px solid rgba(120, 130, 140, .13) } .search-listing li h3 { margin: 0; font-size: 18px } .search-listing li h3 a { color: #41b3f9 } .search-listing li h3 a:hover { text-decoration: underline } .search-listing li a { color: #7ace4c } a.dt-button, button.dt-button, div.dt-button { background: #41b3f9; color: #fff; border-color: #41b3f9 } a.dt-button:hover, button.dt-button:hover, div.dt-button:hover { background: #41b3f9 } a.dt-button:hover:not(.disabled), button.dt-button:hover:not(.disabled), div.dt-button:hover:not(.disabled) { background: #f7fafc; color: #263238; border-color: rgba(120, 130, 140, .13) } .dataTables_filter input { border: 1px solid rgba(120, 130, 140, .13) } table.dataTable.display tbody tr.even>.sorting_1, table.dataTable.display tbody tr.odd>.sorting_1, table.dataTable.display tbody tr:hover>.sorting_1, table.dataTable.order-column.hover tbody tr:hover>.sorting_1, table.dataTable.order-column.stripe tbody tr.even>.sorting_1, table.dataTable.order-column.stripe tbody tr.odd>.sorting_1 { background: 0 0 } .note-editor { border: 1px solid rgba(120, 130, 140, .13) } .note-editor .panel-heading { padding: 6px 10px 10px } .page-aside { position: relative } .left-aside { position: absolute; background: #fff; border-right: 1px solid rgba(120, 130, 140, .13); padding: 20px; width: 250px; height: 100% } .right-aside { padding: 20px; margin-left: 250px } .right-aside .contact-list th { white-space: nowrap } .right-aside .contact-list td { vertical-align: middle; white-space: nowrap; padding: 25px 10px } .right-aside .contact-list td img { width: 30px } .contact-list th { white-space: nowrap } .contact-list td { vertical-align: middle; padding: 25px 10px; white-space: nowrap } .contact-list td img { width: 30px } .list-style-none { margin: 0; padding: 0 } .list-style-none li { list-style: none; margin: 0 } .list-style-none li.box-label a { font-weight: 500 } .list-style-none li.divider { margin: 10px 0; height: 1px; background: rgba(120, 130, 140, .13) } .list-style-none li a { padding: 15px 10px; display: block; color: #313131 } .list-style-none li a:hover { color: #2cabe3 } .list-style-none li a span { float: right } .chat-main-box { position: relative; background: #fff; overflow: hidden } .chat-main-box .chat-left-aside { position: absolute; width: 250px; z-index: 9; top: 0; border-right: 1px solid rgba(120, 130, 140, .13) } .chat-main-box .chat-left-aside .open-panel { display: none; cursor: pointer; position: absolute; left: -webkit-calc(99%); top: 50%; z-index: 100; background-color: #fff; -webkit-box-shadow: 1px 0 3px rgba(0, 0, 0, .2); box-shadow: 1px 0 3px rgba(0, 0, 0, .2); border-radius: 0 100px 100px 0; line-height: 1; padding: 15px 8px 15px 4px } .chat-main-box .chat-left-aside .chat-left-inner .form-control { height: 60px } .chat-main-box .chat-left-aside .chat-left-inner .style-none { padding: 0 } .chat-main-box .chat-left-aside .chat-left-inner .style-none li { list-style: none; overflow: hidden } .chat-main-box .chat-left-aside .chat-left-inner .style-none li a { padding: 20px } .chat-main-box .chat-left-aside .chat-left-inner .style-none li a.active, .chat-main-box .chat-left-aside .chat-left-inner .style-none li a:hover { background: #f7fafc } .chat-main-box .chat-right-aside { margin-left: 250px } .chat-main-box .chat-right-aside .chat-list { max-height: none; height: 100%; padding-top: 40px } .chat-main-box .chat-right-aside .chat-list .chat-text { border-radius: 6px } .chat-main-box .chat-right-aside .send-chat-box { position: relative } .chat-main-box .chat-right-aside .send-chat-box .form-control { border: none; border-top: 1px solid rgba(120, 130, 140, .13); resize: none; height: 80px; padding-right: 180px } .chat-main-box .chat-right-aside .send-chat-box .form-control:focus { border-color: rgba(120, 130, 140, .13) } .chat-main-box .chat-right-aside .send-chat-box .custom-send { position: absolute; right: 20px; bottom: 10px } .chat-main-box .chat-right-aside .send-chat-box .custom-send .cst-icon { color: #313131; margin-right: 10px } .el-element-overlay .white-box { padding: 0 } .el-element-overlay .el-card-item { position: relative; padding-bottom: 25px } .el-element-overlay .el-card-item .el-card-avatar { margin-bottom: 15px } .el-element-overlay .el-card-item .el-card-content { text-align: center } .el-element-overlay .el-card-item .el-card-content h3 { margin: 0 } .el-element-overlay .el-card-item .el-card-content a { color: #313131 } .el-element-overlay .el-card-item .el-card-content a:hover { color: #2cabe3 } .el-element-overlay .el-card-item .el-overlay-1 { width: 100%; height: 100%; overflow: hidden; position: relative; text-align: center; cursor: default } .el-element-overlay .el-card-item .el-overlay-1 img { display: block; position: relative; -webkit-transition: all .4s linear; transition: all .4s linear; width: 100%; height: auto } .el-element-overlay .el-card-item .el-overlay-1:hover img { -ms-transform: scale(1.2) translateZ(0); -webkit-transform: scale(1.2) translateZ(0) } .el-element-overlay .el-card-item .el-overlay-1 .el-info { text-decoration: none; display: inline-block; text-transform: uppercase; color: #fff; background-color: transparent; filter: alpha(opacity=0); -webkit-transition: all .2s ease-in-out; transition: all .2s ease-in-out; padding: 0; margin: auto; position: absolute; top: 50%; left: 0; right: 0; transform: translateY(-50%) translateZ(0); -webkit-transform: translateY(-50%) translateZ(0); -ms-transform: translateY(-50%) translateZ(0) } .el-element-overlay .el-card-item .el-overlay-1 .el-info>li { list-style: none; display: inline-block; margin: 0 3px } .el-element-overlay .el-card-item .el-overlay-1 .el-info>li a { border-color: #fff; color: #fff; padding: 12px 15px 10px } .el-element-overlay .el-card-item .el-overlay-1 .el-info>li a:hover { background: #f33155; border-color: #f33155 } .el-element-overlay .el-card-item .el-overlay { width: 100%; height: 100%; position: absolute; overflow: hidden; top: 0; left: 0; opacity: 0; background-color: rgba(0, 0, 0, .7); -webkit-transition: all .4s ease-in-out; transition: all .4s ease-in-out } .el-element-overlay .el-card-item .el-overlay-1:hover .el-overlay { opacity: 1; filter: alpha(opacity=100); -webkit-transform: translateZ(0); -ms-transform: translateZ(0); transform: translateZ(0) } .el-element-overlay .el-card-item .el-overlay-1 .scrl-dwn { top: -100% } .el-element-overlay .el-card-item .el-overlay-1 .scrl-up { top: 100%; height: 0 } .el-element-overlay .el-card-item .el-overlay-1:hover .scrl-dwn { top: 0 } .el-element-overlay .el-card-item .el-overlay-1:hover .scrl-up { top: 0; height: 100% } .login-sidebar { position: absolute; right: 0; margin-top: 0; height: 100% } .color-table.primary-table thead th { background-color: #7460ee; color: #fff } .color-table.success-table thead th { background-color: #7ace4c; color: #fff } .color-table.info-table thead th { background-color: #41b3f9; color: #fff } .color-table.warning-table thead th { background-color: #fb4; color: #fff } .color-table.danger-table thead th { background-color: #f33155; color: #fff } .color-table.inverse-table thead th { background-color: #4c5667; color: #fff } .color-table.dark-table thead th { background-color: #263238; color: #fff } .color-table.red-table thead th { background-color: #f33155; color: #fff } .color-table.purple-table thead th { background-color: #707cd2; color: #fff } .color-table.muted-table thead th { background-color: #98a6ad; color: #fff } .color-bordered-table.primary-bordered-table { border: 2px solid #7460ee } .color-bordered-table.primary-bordered-table thead th { background-color: #7460ee; color: #fff } .color-bordered-table.success-bordered-table { border: 2px solid #7ace4c } .color-bordered-table.success-bordered-table thead th { background-color: #7ace4c; color: #fff } .color-bordered-table.info-bordered-table { border: 2px solid #41b3f9 } .color-bordered-table.info-bordered-table thead th { background-color: #41b3f9; color: #fff } .color-bordered-table.warning-bordered-table { border: 2px solid #fb4 } .color-bordered-table.warning-bordered-table thead th { background-color: #fb4; color: #fff } .color-bordered-table.danger-bordered-table { border: 2px solid #f33155 } .color-bordered-table.danger-bordered-table thead th { background-color: #f33155; color: #fff } .color-bordered-table.inverse-bordered-table { border: 2px solid #4c5667 } .color-bordered-table.inverse-bordered-table thead th { background-color: #4c5667; color: #fff } .color-bordered-table.dark-bordered-table { border: 2px solid #263238 } .color-bordered-table.dark-bordered-table thead th { background-color: #263238; color: #fff } .color-bordered-table.red-bordered-table { border: 2px solid #f33155 } .color-bordered-table.red-bordered-table thead th { background-color: #f33155; color: #fff } .color-bordered-table.purple-bordered-table { border: 2px solid #707cd2 } .color-bordered-table.purple-bordered-table thead th { background-color: #707cd2; color: #fff } .color-bordered-table.muted-bordered-table { border: 2px solid #98a6ad } .color-bordered-table.muted-bordered-table thead th { background-color: #98a6ad; color: #fff } .full-color-table.full-primary-table { background-color: rgba(171, 140, 228, .8) } .full-color-table.full-primary-table thead th { background-color: #7460ee; border: 0!important; color: #fff } .full-color-table.full-primary-table tbody td { border: 0!important; color: #fff } .full-color-table.full-primary-table tr:hover { background-color: #7460ee } .full-color-table.full-success-table { background-color: rgba(0, 194, 146, .8) } .full-color-table.full-success-table thead th { background-color: #7ace4c; border: 0!important; color: #fff } .full-color-table.full-success-table tbody td { border: 0!important; color: #fff } .full-color-table.full-success-table tr:hover { background-color: #7ace4c } .full-color-table.full-info-table { background-color: rgba(3, 169, 243, .8) } .full-color-table.full-info-table thead th { background-color: #41b3f9; border: 0!important; color: #fff } .full-color-table.full-info-table tbody td { border: 0!important; color: #fff } .full-color-table.full-info-table tr:hover { background-color: #41b3f9 } .full-color-table.full-warning-table { background-color: rgba(254, 193, 7, .8) } .full-color-table.full-warning-table thead th { background-color: #fb4; border: 0!important; color: #fff } .full-color-table.full-warning-table tbody td { border: 0!important; color: #fff } .full-color-table.full-warning-table tr:hover { background-color: #fb4 } .full-color-table.full-danger-table { background-color: rgba(251, 150, 120, .8) } .full-color-table.full-danger-table thead th { background-color: #f33155; border: 0!important; color: #fff } .full-color-table.full-danger-table tbody td { border: 0!important; color: #fff } .full-color-table.full-danger-table tr:hover { background-color: #f33155 } .full-color-table.full-inverse-table { background-color: rgba(76, 86, 103, .8) } .full-color-table.full-inverse-table thead th { background-color: #4c5667; border: 0!important; color: #fff } .full-color-table.full-inverse-table tbody td { border: 0!important; color: #fff } .full-color-table.full-inverse-table tr:hover { background-color: #4c5667 } .full-color-table.full-dark-table { background-color: rgba(43, 43, 43, .8) } .full-color-table.full-dark-table thead th { background-color: #263238; border: 0!important; color: #fff } .full-color-table.full-dark-table tbody td { border: 0!important; color: #fff } .full-color-table.full-dark-table tr:hover { background-color: #263238 } .full-color-table.full-red-table { background-color: rgba(251, 58, 58, .8) } .full-color-table.full-red-table thead th { background-color: #f33155; border: 0!important; color: #fff } .full-color-table.full-red-table tbody td { border: 0!important; color: #fff } .full-color-table.full-red-table tr:hover { background-color: #f33155 } .full-color-table.full-purple-table { background-color: rgba(150, 117, 206, .8) } .full-color-table.full-purple-table thead th { background-color: #707cd2; border: 0!important; color: #fff } .full-color-table.full-purple-table tbody td { border: 0!important; color: #fff } .full-color-table.full-purple-table tr:hover { background-color: #707cd2 } .full-color-table.full-muted-table { background-color: rgba(152, 166, 173, .8) } .full-color-table.full-muted-table thead th { background-color: #98a6ad; border: 0!important; color: #fff } .full-color-table.full-muted-table tbody td { border: 0!important; color: #fff } .full-color-table.full-muted-table tr:hover { background-color: #98a6ad } .floating-labels .form-group { position: relative } .floating-labels .form-control { font-size: 20px; padding: 10px 10px 10px 0; display: block; border: none; border-bottom: 1px solid #e4e7ea } .floating-labels select.form-control>option { font-size: 14px } .has-error .form-control { border-bottom: 1px solid #f33155 } .has-warning .form-control { border-bottom: 1px solid #fb4 } .has-success .form-control { border-bottom: 1px solid #7ace4c } .floating-labels .form-control:focus { outline: 0; border: none } .floating-labels label { color: #313131; font-size: 16px; position: absolute; cursor: auto; font-weight: 400; top: 10px; transition: .2s ease all; -moz-transition: .2s ease all; -webkit-transition: .2s ease all } .floating-labels .form-control:focus~label, .floating-labels .form-control:valid~label { top: -20px; font-size: 12px; color: #7460ee } .floating-labels .bar { position: relative; display: block } .floating-labels .bar:after, .floating-labels .bar:before { content: ''; height: 2px; width: 0; bottom: 1px; position: absolute; background: #7460ee; transition: .2s ease all; -moz-transition: .2s ease all; -webkit-transition: .2s ease all } .floating-labels .bar:before { left: 50% } .floating-labels .bar:after { right: 50% } .floating-labels .form-control:focus~.bar:after, .floating-labels .form-control:focus~.bar:before { width: 50% } .floating-labels .highlight { position: absolute; height: 60%; width: 100px; top: 25%; left: 0; pointer-events: none; opacity: .5 } .floating-labels .input-lg, .floating-labels .input-lg~label { font-size: 24px } .floating-labels .input-sm, .floating-labels .input-sm~label { font-size: 16px } .has-warning .bar:after, .has-warning .bar:before { background: #fb4 } .has-success .bar:after, .has-success .bar:before { background: #7ace4c } .has-error .bar:after, .has-error .bar:before { background: #f33155 } .has-warning .form-control:focus~label, .has-warning .form-control:valid~label { color: #fb4 } .has-success .form-control:focus~label, .has-success .form-control:valid~label { color: #7ace4c } .has-error .form-control:focus~label, .has-error .form-control:valid~label { color: #f33155 } .has-feedback label~.t-0 { top: 0 } .table.dataTable, table.dataTable { width: 99.8%!important } table.dataTable thead .sorting::after, table.dataTable thead .sorting_asc::after, table.dataTable thead .sorting_desc::after { float: none; padding-left: 10px } .re ul.two-part li i, .re ul.two-part li span { font-size: 36px } .bg-light h4 { font-weight: 700 } .agent-contact, .pro-desc { font-size: 12px } .form-agent-inq .form-group { margin-bottom: 10px } .agent-info { max-height: 358px; height: 358px; background: #f7fafc } .pro-list { margin-top: 15px } .pro-detail, .pro-img { display: table-cell; vertical-align: top } .pro-detail h5 a { color: #313131; line-height: 20px; font-weight: 500 } .pro-box .pro-list-img { display: block; height: 210px; position: relative; overflow: hidden } .pro-box .pro-label { position: absolute; text-transform: uppercase; top: 0; right: 0; border-radius: 2px; padding: 5px; font-size: 80% } .pro-col-label { padding: 7px; width: 26%; display: block; margin-top: -15px; margin-left: 37%; border: 1px solid rgba(120, 130, 140, .13); text-transform: uppercase } .pro-box .pro-label-img { position: absolute; top: 30px; right: 30px } .pro-box.pro-horizontal pro-content { width: 100%; height: 210px } .pro-content .pro-list-details { height: 138px; max-height: 142px; border-bottom: 1px solid rgba(120, 130, 140, .13); border-right: 1px solid rgba(120, 130, 140, .13) } .pro-content .pro-list-info { border-bottom: 1px solid rgba(120, 130, 140, .13) } .pro-agent .agent-name h5, .pro-agent .agent-name small, .pro-agent-col-3 .agent-name h5, .pro-agent-col-3 .agent-name small, .pro-content .pro-list-details h3, .pro-content .pro-list-details h4, .pro-content-3-col .pro-list-details h3, .pro-content-3-col .pro-list-details h4, .pro-content-3-col .pro-list-details h4 small, .pro-list-info ul.pro-info li, .pro-list-info-3-col ul.pro-info li, .pro-location span, ul.pro-info li span.label { font-weight: 500 } .pro-list-info ul.pro-info, .pro-list-info-3-col ul.pro-info { padding: 16px 10px 10px; list-style: none } .pro-list-info ul.pro-info li { padding: 10px 0 10px 20px; font-size: 12px } ul.pro-info li span.label { width: 25px; height: 25px; padding: 8px; border-radius: 50%; margin-top: -4px; margin-right: 15px; font-size: 12px } ul.pro-amenities li span img, ul.pro-info li span img { margin-top: -8px; padding-right: 12px } .pro-agent .agent-img a img, .pro-agent-col-3 .agent-img a img { border: 3px solid #fff; box-shadow: 1px 1px 1px rgba(120, 130, 140, .13) } .pro-agent .agent-img, .pro-agent .agent-name, .pro-agent-col-3 .agent-img, .pro-agent-col-3 .agent-name { float: left } .pro-agent .agent-img { padding-top: 12px } .pro-agent .agent-name { padding: 10px 0 0 15px } .pro-location span { padding-top: 27px } .pro-content-3-col { padding: 15px; background: #f7fafc } .pro-content-3-col .pro-list-details h4 small { color: #f33155 } .pro-list-info-3-col ul.pro-info li { padding: 10px 5px } .pro-agent-col-3 .agent-img { padding: 15px } .pro-agent-col-3 .agent-name { padding: 15px 15px 15px 5px } ul.pro-amenities { list-style: none; padding: 8px 0 } ul.pro-amenities li { padding: 10px 0; font-size: 12px } ul.pro-amenities li span i { padding-right: 12px } .pro-rd .table>tbody>tr>td:first-child { font-weight: 500 } .pro-rd .table>tbody>tr>td, .pro-rd .table>tbody>tr>th { border: none; padding: 8px 8px 8px 0; font-size: 12px } .pd-agent-info { max-height: 200px; height: 200px; background: #f7fafc; margin-top: 15px } .pd-agent-contact, .pd-agent-inq { padding: 25px } .pro-add-form .checkbox label, .pro-add-form .radio label { font-weight: 100 } .plugin-details { display: none } .plugin-details-active { display: block } .register-box { max-width: 600px; margin: 0 auto; padding-top: 2% } .step-register { position: absolute; height: 100% } .material-icon-list-demo .icons div { width: 33%; padding: 15px; display: inline-block; line-height: 40px } .material-icon-list-demo .icons div i { font-size: 24px; vertical-align: middle; margin-right: 10px } .material-icon-list-demo .icons div:hover { background: #f7fafc } .full-width { display: inline-block; width: 100%; height: auto } @media (max-width: 1680px) { .weather-with-bg .wt-counter li { padding: 10px 1px } } @media (max-width: 1460px) { .weather-with-bg .wt-counter li { padding: 10px 0 } .weather-with-bg .wt-counter li a { min-width: 38px; margin-bottom: 7px; height: 43px; padding: 10px } } @media (max-width: 1350px) { .carousel .item h3 { font-size: 17px; height: 90px } .inbox-center a { width: 400px } .new-login-register .lg-info-panel { width: 450px } .new-login-register .new-login-box { margin-left: 500px } } @media (min-width: 1170px) { .app-search .form-control:focus { width: 300px } .hide-sidebar .top-left-part { width: auto } .hide-sidebar .top-left-part .logo span { display: none } .hide-sidebar .sidebar { left: -240px; transition: .5s ease-out } .hide-sidebar #page-wrapper { margin-left: 0 } .hide-sidebar .footer { left: 0 } } @media (min-width: 768px) { #page-wrapper { position: inherit; margin: 0 0 0 240px } .navbar-default { position: relative; width: 100%; top: 0 } .sidebar { z-index: 1001; position: fixed; width: 240px; padding-top: 0; height: 100%; transition: .05s ease-in } .sidebar:hover { width: 240px } .fix-header .navbar-static-top { position: fixed; z-index: 1010 } .fix-header #page-wrapper { margin-top: 60px } } .navbar-top-links .dropdown-alerts, .navbar-top-links .dropdown-messages, .navbar-top-links .dropdown-tasks { margin-left: auto } .mail_listing { border-left: 1px solid rgba(120, 130, 140, .13); padding-left: 20px } .inbox-panel { padding-right: 20px } .top-minus { margin-top: -62px; float: right } @media (max-width: 1170px) { .content-wrapper .sidebar { left: -240px } .content-wrapper #page-wrapper { margin-left: 0 } .content-wrapper .footer, .content-wrapper.show-sidebar .sidebar { left: 0 } .col-in { padding: 15px 0 } .col-in li.col-middle { width: 100% } } @media (max-width: 1023px) { .b-r-none { border-right: 0 } .carousel-inner h3 { height: 90px; overflow: hidden } .inbox-center a { width: 300px } .new-login-register .lg-info-panel { display: none } .new-login-register .new-login-box { margin: 10% auto 0 } } @media (max-width: 767px) { .navbar-top-links { float: left } .navbar-top-links .profile-pic img { margin-right: 0 } .top-left-part { width: 60px } .navbar-top-links>li:last-child { margin-right: 0 } .navbar-top-links>li>a { padding: 0 12px } .navbar-top-links .dropdown-alerts, .navbar-top-links .dropdown-messages, .navbar-top-links .dropdown-tasks { width: 260px } .show-sidebar .sidebar { width: 240px; top: 0 } .show-sidebar .sidebar .hide-menu { display: inline } .show-sidebar .sidebar .nav-small-cap { display: block } .show-sidebar .sidebar .sidebar-head { width: 240px; display: block } .sidebar { z-index: 1001; position: fixed; width: 0; padding-top: 0; height: 100% } .sidebar-head { width: 0; display: none } #page-wrapper { margin: 0 } .row-in-br { border-right: 0; border-bottom: 1px solid rgba(120, 130, 140, .13) } .bg-title .breadcrumb { float: left; margin-top: 0; margin-bottom: 10px } ul.timeline:before { left: 40px } ul.timeline>li>.timeline-panel { width: calc(100% - 90px) } ul.timeline>li>.timeline-badge { top: 16px; left: 15px; margin-left: 0 } ul.timeline>li>.timeline-panel { float: right } ul.timeline>li>.timeline-panel:before { right: auto; left: -15px; border-right-width: 15px; border-left-width: 0 } ul.timeline>li>.timeline-panel:after { right: auto; left: -14px; border-right-width: 14px; border-left-width: 0 } .wizard-steps>li { display: block } .dropdown .dropdown-tasks, .dropdown .mailbox { left: -94px } .fix-header .navbar-static-top { position: fixed; top: 0; width: 100% } .fix-header #page-wrapper { margin-top: 60px } .mega-dropdown-menu { height: 340px; overflow: auto } .left-aside { position: relative; width: 100%; border: 0 } .right-aside { margin-left: 0 } .chat-main-box .chat-left-aside { left: -250px; transition: .5s ease-in; background: #fff } .chat-main-box .chat-left-aside.open-pnl { left: 0 } .chat-main-box .chat-left-aside .open-panel { display: block } .chat-main-box .chat-right-aside { margin: 0 } .table-responsive.pro-rd { border: none } #msform fieldset, .login-register, .step-register { position: relative } .mega-dropdown-menu { padding-left: 20px } .calendar-widget .cal-left { position: relative; width: 100% } .calendar-widget .cal-left .cal-btm-text { position: relative; bottom: 0; padding-top: 30px } .calendar-widget .cal-right { width: 100% } .calendar-widget .cal-right .cal-table td { padding: 15px 0 } .calendar-widget .cal-right .cal-table td h1 { padding-left: 20px } .error-body h1 { font-size: 80px; line-height: 100px } .weather-with-bg .wt-top .wt-img h1 { font-size: 24px; line-height: 24px } .manage-table { margin: 0 } .dp-table img { width: 50px } .earning-box li .er-row .er-text { width: 37% } .earning-box li .er-row .er-count { font-size: 24px } .sidebar .nav-second-level li a, .sidebar:hover .nav-second-level li a { padding-left: 40px } .sidebar .nav-third-level li a, .sidebar:hover .nav-third-level li a { padding-left: 60px } } @media (max-width: 480px) { .vtabs .tabs-vertical { width: auto } .stat-item { padding-right: 0 } .login-box { width: 100% } .pro-content .pro-list-details { height: 100px; border-right: none } .pro-list-info ul.pro-info li { padding: 10px 0 } .pro-list-info ul.pro-info { padding-left: 0 } .pro-agent .agent-img { padding-top: 3px } .pro-agent .agent-name { padding: 2px 0 10px 15px } .new-login-register .lg-info-panel { display: none } .new-login-register .new-login-box { margin: 10% auto 0; width: 300px } } .currency-logo-sprite { margin-right: 8px; margin-top: 1px; float: left; } ================================================ FILE: templates/dashboard_assets/js/custom.js ================================================ /*jslint browser: true*/ /*global $, jQuery, alert*/ $(document).ready(function () { 'use strict' var body = $('body') $(function () { $('.preloader').fadeOut() }) /* =========================================================== Loads the correct sidebar on window load. collapses the sidebar on window resize. Sets the min-height of #page-wrapper to window size. =========================================================== */ $(function () { var set = function () { var topOffset = 60, width = (window.innerWidth > 0) ? window.innerWidth : this.screen.width, height = ((window.innerHeight > 0) ? window.innerHeight : this.screen.height) - 1 /* ===== This is for resizing window ===== */ if (width < 1170) { body.addClass('content-wrapper') $('.sidebar-nav, .slimScrollDiv').css('overflow-x', 'visible').parent().css('overflow', 'visible') } else { body.removeClass('content-wrapper') } height = height - topOffset if (height < 1) { height = 1 } if (height > topOffset) { $('#page-wrapper').css('min-height', (height) + 'px') } }, url = window.location, element = $('ul.nav a').filter(function () { return this.href === url || url.href.indexOf(this.href) === 0 }).addClass('active').parent().parent().addClass('in').parent() if (element.is('li')) { element.addClass('active') } $(window).ready(set) $(window).bind('resize', set) }) /* ===== Tooltip Initialization ===== */ $(function () { $('[data-toggle="tooltip"]').tooltip() }) /* ===== Popover Initialization ===== */ $(function () { $('[data-toggle="popover"]').popover() }) /* ===== Task Initialization ===== */ $('.list-task li label').on('click', function () { $(this).toggleClass('task-done') }) $('.settings_box a').on('click', function () { $('ul.theme_color').toggleClass('theme_block') }) /* ===== Collepsible Toggle ===== */ $('.collapseble').on('click', function () { $('.collapseblebox').fadeToggle(350) }) /* ===== Sidebar ===== */ $('.slimscrollright').slimScroll({ height: '100%', position: 'right', size: '5px', color: '#dcdcdc' }) $('.slimscrollsidebar').slimScroll({ height: '100%', position: 'right', size: '6px', color: 'rgba(0,0,0,0.3)' }) /* ===== Resize all elements ===== */ body.trigger('resize') /* ===== Visited ul li ===== */ $('.visited li a').on('click', function (e) { $('.visited li').removeClass('active') var $parent = $(this).parent() if (!$parent.hasClass('active')) { $parent.addClass('active') } e.preventDefault() }) /* ===== Login and Recover Password ===== */ $('#to-recover').on('click', function () { $('#loginform').slideUp() $('#recoverform').fadeIn() }) /* ================================================================= Update 1.5 this is for close icon when navigation open in mobile view ================================================================= */ $('.navbar-toggle').on('click', function () { $('.navbar-toggle i').toggleClass('ti-menu').addClass('ti-close') }) }) ================================================ FILE: templates/dashboard_assets/js/jquery.slimscroll.js ================================================ !function(e){e.fn.extend({slimScroll:function(i){var o={width:'auto',height:'250px',size:'7px',color:'#000',position:'right',distance:'1px',start:'top',opacity:.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:'#333',railOpacity:.2,railDraggable:!0,railClass:'slimScrollRail',barClass:'slimScrollBar',wrapperClass:'slimScrollDiv',allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:'7px',railBorderRadius:'7px'},s=e.extend(o,i);return this.each(function(){function o(t){if(h){var t=t||window.event,i=0;t.wheelDelta&&(i=-t.wheelDelta/120),t.detail&&(i=t.detail/3);var o=t.target||t.srcTarget||t.srcElement;e(o).closest('.'+s.wrapperClass).is(x.parent())&&r(i,!0),t.preventDefault&&!y&&t.preventDefault(),y||(t.returnValue=!1)}}function r(e,t,i){y=!1;var o=e,r=x.outerHeight()-R.outerHeight();if(t&&(o=parseInt(R.css('top'))+e*parseInt(s.wheelStep)/100*R.outerHeight(),o=Math.min(Math.max(o,0),r),o=e>0?Math.ceil(o):Math.floor(o),R.css({top:o+'px'})),v=parseInt(R.css('top'))/(x.outerHeight()-R.outerHeight()),o=v*(x[0].scrollHeight-x.outerHeight()),i){o=e;var a=o/x[0].scrollHeight*x.outerHeight();a=Math.min(Math.max(a,0),r),R.css({top:a+'px'})}x.scrollTop(o),x.trigger('slimscrolling',~~o),n(),c()}function a(e){window.addEventListener?(e.addEventListener('DOMMouseScroll',o,!1),e.addEventListener('mousewheel',o,!1)):document.attachEvent('onmousewheel',o)}function l(){f=Math.max(x.outerHeight()/x[0].scrollHeight*x.outerHeight(),m),R.css({height:f+'px'});var e=f==x.outerHeight()?'none':'block';R.css({display:e})}function n(){if(l(),clearTimeout(p),v==~~v){if(y=s.allowPageScroll,b!=v){var e=0==~~v?'top':'bottom';x.trigger('slimscroll',e)}}else y=!1;return b=v,f>=x.outerHeight()?void(y=!0):(R.stop(!0,!0).fadeIn('fast'),void(s.railVisible&&E.stop(!0,!0).fadeIn('fast')))}function c(){s.alwaysVisible||(p=setTimeout(function(){s.disableFadeOut&&h||u||d||(R.fadeOut('slow'),E.fadeOut('slow'))},1e3))}var h,u,d,p,g,f,v,b,w='
',m=30,y=!1,x=e(this);if(x.parent().hasClass(s.wrapperClass)){var C=x.scrollTop();if(R=x.closest('.'+s.barClass),E=x.closest('.'+s.railClass),l(),e.isPlainObject(i)){if('height'in i&&'auto'==i.height){x.parent().css('height','auto'),x.css('height','auto');var H=x.parent().parent().height();x.parent().css('height',H),x.css('height',H)}if('scrollTo'in i)C=parseInt(s.scrollTo);else if('scrollBy'in i)C+=parseInt(s.scrollBy);else if('destroy'in i)return R.remove(),E.remove(),void x.unwrap();r(C,!1,!0)}}else if(!(e.isPlainObject(i)&&'destroy'in i)){s.height='auto'==s.height?x.parent().height():s.height;var S=e(w).addClass(s.wrapperClass).css({position:'relative',overflow:'hidden',width:s.width,height:s.height});x.css({overflow:'hidden',width:s.width,height:s.height});var E=e(w).addClass(s.railClass).css({width:s.size,height:'100%',position:'absolute',top:0,display:s.alwaysVisible&&s.railVisible?'block':'none','border-radius':s.railBorderRadius,background:s.railColor,opacity:s.railOpacity,zIndex:90}),R=e(w).addClass(s.barClass).css({background:s.color,width:s.size,position:'absolute',top:0,opacity:s.opacity,display:s.alwaysVisible?'block':'none','border-radius':s.borderRadius,BorderRadius:s.borderRadius,MozBorderRadius:s.borderRadius,WebkitBorderRadius:s.borderRadius,zIndex:99}),D='right'==s.position?{right:s.distance}:{left:s.distance};E.css(D),R.css(D),x.wrap(S),x.parent().append(R),x.parent().append(E),s.railDraggable&&R.bind('mousedown',function(i){var o=e(document);return d=!0,t=parseFloat(R.css('top')),pageY=i.pageY,o.bind('mousemove.slimscroll',function(e){currTop=t+e.pageY-pageY,R.css('top',currTop),r(0,R.position().top,!1)}),o.bind('mouseup.slimscroll',function(e){d=!1,c(),o.unbind('.slimscroll')}),!1}).bind('selectstart.slimscroll',function(e){return e.stopPropagation(),e.preventDefault(),!1}),E.hover(function(){n()},function(){c()}),R.hover(function(){u=!0},function(){u=!1}),x.hover(function(){h=!0,n(),c()},function(){h=!1,c()}),x.bind('touchstart',function(e,t){e.originalEvent.touches.length&&(g=e.originalEvent.touches[0].pageY)}),x.bind('touchmove',function(e){if(y||e.originalEvent.preventDefault(),e.originalEvent.touches.length){var t=(g-e.originalEvent.touches[0].pageY)/s.touchScrollStep;r(t,!0),g=e.originalEvent.touches[0].pageY}}),l(),'bottom'===s.start?(R.css({top:x.outerHeight()-R.outerHeight()}),r(0,!0)):'top'!==s.start&&(r(e(s.start).position().top,null,!0),s.alwaysVisible||R.hide()),a(this)}}),this}}),e.fn.extend({slimscroll:e.fn.slimScroll})}(jQuery) ================================================ FILE: templates/dashboard_assets/manifest.json ================================================ { "start_url": "/", "display": "standalone", "theme_color": "#ff6600", "background_color": "#ffffff", "icons": [ { "src": "https://raw.githubusercontent.com/DeviaVir/zenbot/master/assets/zenbot_square.png", "sizes": "112x112", "type": "image/png" } ] } ================================================ FILE: test/_mocks/collectionService.mock.factory.js ================================================ /* By default, returns a mock collection service, which has - a method getTrades(), which simulates two trade records in the DB - a method getResumeMarkers(), */ module.exports = (opts) => { if (opts === undefined) opts = { } var tradesArray if (opts.tradesArray !== undefined && opts.tradesArray !== null) tradesArray = opts.tradesArray else tradesArray = [{id: 'stub.BTC-USD-3000', trade_id: 3000, time: 99992, selector: 'stub.BTC-USD' }, {id: 'stub.BTC-USD-3001', trade_id: 3001, time: 99994, selector: 'stub.BTC-USD'}] var resumeMarkersArray if (opts.resumeMarkersArray !== undefined && opts.resumeMarkersArray !== null) resumeMarkersArray = opts.resumeMarkersArray else resumeMarkersArray = [{from: 2994, to: 2998, oldest_time: 99960, newest_time: 99986}] var mockUpdateFunction if (opts.mockUpdateFunction !== undefined && opts.mockUpdateFunction !== null) mockUpdateFunction = opts.mockUpdateFunction var mockDeleteManyFunction if (opts.mockDeleteManyFunction !== undefined && opts.mockDeleteManyFunction !== null) mockDeleteManyFunction = opts.mockDeleteManyFunction var mockInsertManyFunction if (opts.mockInsertManyFunction !== undefined && opts.mockInsertManyFunction !== null) mockInsertManyFunction = opts.mockInsertManyFunction var mockFindOneFunction if (opts.mockFindOneFunction !== undefined && opts.mockFindOneFunction !== null) mockFindOneFunction = opts.mockFindOneFunction var findOneReturnTrade if (opts.findOneReturnTrade !== undefined && opts.findOneReturnTrade !== null) findOneReturnTrade = opts.findOneReturnTrade var rtn = { getTrades: () => { return { findOne: (query) => { if (mockFindOneFunction) mockFindOneFunction(query) return { then: (func) => { func(findOneReturnTrade) } } }, find: () => { return { limit: (/* num */) => { return { toArray: (func) => { func(null, tradesArray) } } }, toArray: (func) => { func(null, tradesArray) } } }, insert: (trade) => { return { then: (cb/*, err*/) => { // TODO: should this be (err, cb) instead? cb(trade) } } }, }}, getResumeMarkers: () => { return { find: () => { return { toArray: (func) => { func(null, resumeMarkersArray) } } }, save: (doc, func) => { func(null, null) }, update: (opts, doc, func) => { func(null, null) if (mockUpdateFunction) mockUpdateFunction(opts, doc, func) }, deleteMany: (q, cb) => { cb(); if (mockDeleteManyFunction) mockDeleteManyFunction(q) }, insertMany: (q, cb) => { cb(); if (mockInsertManyFunction) mockInsertManyFunction(q) } } } } // collection service return rtn } ================================================ FILE: test/_mocks/consumeAndProcessService.mock.factory.js ================================================ module.exports = (opts) => { if (opts === undefined) { opts = { } } if (opts.onSuccessFunc === undefined) opts.onSuccessFunc = (cb) => { cb( {trade_id: 3001} ) } var rtn = { setOnConsumeFunc: () => { }, setOnProcessFunc: () => { }, setAfterOnConsumeFunc: () => { }, setAfterOnProcessFunc: () => { }, go: () => { return { then: (cb /*, err*/) => { opts.onSuccessFunc(cb) } }} } return rtn } ================================================ FILE: test/_mocks/exchangeService.mock.factory.js ================================================ /* By default, returns a mock exchange service, which has a backward history scan, and returns two mock trades. */ module.exports = (opts) => { var selectorObject = {normalized: 'stub.BTC-USD', exchange_id: 'stub', asset: 'BTC', currency: 'USD' } if (opts === undefined) opts = { } var rtn = { BACKWARD: 'backward', FORWARD: 'forward', getSelector: () => { return selectorObject }, getExchange: undefined } // exchange service var getTradesOptionsObservingFunc if (opts.getTradesOptionsObservingFunc !== undefined && opts.getTradesOptionsObservingFunc !== null) getTradesOptionsObservingFunc = opts.getTradesOptionsObservingFunc var tradesArray = [{id: 'stub.BTC-USD-3000', trade_id: 3000, time: 99992 }, {id: 'stub.BTC-USD-3001', trade_id: 3001, time: 99994}] if (opts.tradesArray !== undefined && opts.tradesArray !== null) tradesArray = opts.tradesArray if (opts.exchangeTradesArray !== undefined && opts.exchangeTradesArray !== null) tradesArray = opts.exchangeTradesArray var getTradesFunc if (opts.getTradesFunc !== undefined && opts.getTradesFunc !== null) getTradesFunc = opts.getTradesFunc else getTradesFunc = (opts, func) => { if (typeof getTradesOptionsObservingFunc == 'function') getTradesOptionsObservingFunc(opts) func(null, tradesArray) } var direction = opts.direction || 'backward' rtn.getExchange = () => { return { historyScan: direction, historyScanUsesTime: opts.historyScanUsesTime, getTrades: getTradesFunc } } return rtn } ================================================ FILE: test/_mocks/resumeMarkerService.mock.factory.js ================================================ module.exports = (opts) => { if (opts === undefined) opts = { } if (opts.tradeFunction === undefined) opts.tradeFunction = (tradeId) => { return tradeId } return { isInRange: () => { return false }, ping: opts.tradeFunction, load: (cb) => { cb() }, flush: (cb) => { cb() } } // resume-marker service } ================================================ FILE: test/_mocks/tradeService.mock.factory.js ================================================ /* By default, returns a mock trade service, which returns no trades. Set opts.tradesArray to return trades. Y'know, in a mock, or something. */ module.exports = (opts) => { if (opts === undefined) opts = { } if (opts.tradesArray === undefined) opts.tradesArray = [] return { getInitialOptsObject: () => { }, getTrades: (/*tradeSearchOpts*/) => { return { then: (cb) => { cb( opts.tradesArray ) } }} } // trade service } ================================================ FILE: test/_specs/commands/backfill/backfill.consume.function.test.js ================================================ var mock = require('mock-require') var tradeServiceFactory = require('../../../../test/_mocks/tradeService.mock.factory') describe('The Backfill Consume function', function() { var queue beforeEach(function() { mock('../../../../lib/services/trades-service', tradeServiceFactory) queue = { enqueue: function() { }, dequeue: function() { } } spyOn(queue, 'enqueue').and.returnValue({ }) }) afterEach(function(){ mock.stopAll() }) describe('consumes trades from the trade service, indicates the next step should be Processing, rather than Exit', function() { it('', function() { var callback = jasmine.createSpy('callback') var instance = require('../../../../commands/backfill/backfill.consume.function')({tradesArray: [{trade_id:3001, time:1517787104902}, {trade_id:3000, time:1517787104900}]}) instance(undefined, queue, callback) expect(callback.calls.count()).toEqual(1) expect(callback).toHaveBeenCalledWith(null, 'cp_process', 3000) expect(queue.enqueue).toHaveBeenCalledWith([{trade_id: 3001, time: 1517787104902}, {trade_id: 3000, time: 1517787104900}]) }) }) describe('consumes trades from the trade service, indicates the next step should be Exit, rather than Processing', function() { it('', function() { var callback = jasmine.createSpy('callback') var instance = require('../../../../commands/backfill/backfill.consume.function')({}) instance(undefined, queue, callback) expect(callback.calls.count()).toEqual(1) expect(callback).toHaveBeenCalledWith(null, 'cp_exit', undefined) expect(queue.enqueue).not.toHaveBeenCalled() }) }) }) ================================================ FILE: test/_specs/commands/backfill/backfill.function.test.js ================================================ var mock = require('mock-require') var consumeAndProcessServiceFactory = require('../../../_mocks/consumeAndProcessService.mock.factory') describe('The Backfill function', function() { beforeEach(function() { mock('../../../../lib/services/consume-and-process-service', consumeAndProcessServiceFactory) // DEBUGGING process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason) // application specific logging, throwing an error, or other logic here }) }) afterEach(function(){ mock.stopAll() }) it('uses consumeAndProcessService to get the expected value', function() { var instance = require('../../../../commands/backfill/backfill.function')({}) instance(10000).then((finalTrade) => { expect(finalTrade).toEqual({trade_id: 3001}) // this is the last trade defined by default to be returned from the mock consume and process service. }) }) }) ================================================ FILE: test/_specs/commands/backfill/backfill.process.function.test.js ================================================ var mock = require('mock-require') var collectionServiceFactory = require('../../../../test/_mocks/collectionService.mock.factory') var exchangeServiceFactory = require('../../../../test/_mocks/exchangeService.mock.factory') describe('The Backfill Process function', function() { var queue beforeEach(function() { mock('../../../../lib/services/collection-service', collectionServiceFactory) mock('../../../../lib/services/exchange-service', exchangeServiceFactory) mock('../../../../lib/_data-structures/Queue', queue) queue = { enqueue: function() { }, dequeue: function() { } } }) afterEach(function(){ mock.stopAll() }) describe('processes trades ', function() { beforeEach(function () { spyOn(queue, 'dequeue').and.returnValue([{trade_id:3002, time:1517787104904}, {trade_id:3001, time:1517787104902}, {trade_id:3000, time:1517787104900}]) }) it('when all are considered new', function() { var callback = jasmine.createSpy('callback') var instance = mock.reRequire('../../../../commands/backfill/backfill.process.function')({}) var targetTimeInMillis = 1517787104899 instance(targetTimeInMillis, queue, (trade) => { return trade.trade_id }, callback) expect(queue.dequeue.calls.count()).toEqual(1) expect(callback.calls.count()).toEqual(1) expect(callback).toHaveBeenCalledWith(null, false, 3000, {trade_id:3000, time:1517787104900}) }) }) describe('indicates exit condition was reached when one of the trades is past our time limit', function() { beforeEach(function () { spyOn(queue, 'dequeue').and.returnValue([{trade_id:3002, time:1517787104904}, {trade_id:3001, time:1517787104902}, {trade_id:3000, time:1517787104900}]) }) it('', function() { var callback = jasmine.createSpy('callback') var instance = mock.reRequire('../../../../commands/backfill/backfill.process.function')({}) var targetTimeInMillis = 1517787104901 instance(targetTimeInMillis, queue, (trade) => { return trade.trade_id }, callback) expect(queue.dequeue.calls.count()).toEqual(1) expect(callback.calls.count()).toEqual(1) expect(callback).toHaveBeenCalledWith(null, true, 3001, {trade_id:3001, time:1517787104902}) }) }) // TODO xdescribe('does not insert records that have already been seen', function() { beforeEach(function () { spyOn(queue, 'dequeue').and.returnValue([{trade_id:3002, time:1517787104904}, {trade_id:3001, time:1517787104902}, {trade_id:3000, time:1517787104900}]) }) it('', function() { var callback = jasmine.createSpy('callback') var instance = require('../../../../commands/backfill/backfill.process.function')({}) var targetTimeInMillis = 1517787104900 instance(targetTimeInMillis, queue, callback) expect(queue.dequeue.calls.count()).toEqual(1) expect(callback.calls.count()).toEqual(1) expect(callback).toHaveBeenCalledWith(null, false, {trade_id: 3002, time: 1517787104904}) // TODO: How to check that theFunction only called the mockCollectionService twice? // Because there should only be two inserts when the third is reported as 'already seen'. }) }) }) ================================================ FILE: test/_specs/lib/services/collections-service.test.js ================================================ var service = require('../../../../lib/services/collection-service') describe('Collections Service', function() { describe(' trades ', function() { it('is available', function() { expect(service).not.toBe(undefined) }), it('returns the expected objects', function() { var instance = service({db:{mongo:{collection: function() { return { createIndex: function() { }} } }}}) var rtn = instance.getTrades() expect(rtn).toBeDefined() }) }), describe(' resume_markers ', function() { it('is available', function() { expect(service).not.toBe(undefined) }), it('returns the expected objects', function() { var instance = service({db:{mongo:{collection: function() { return { createIndex: function() { }} } }}}) var rtn = instance.getResumeMarkers() expect(rtn).toBeDefined() }) }) }) ================================================ FILE: test/_specs/lib/services/consume-and-process-service.test.js ================================================ var mock = require('mock-require') var service = require('../../../../lib/services/consume-and-process-service') var resumeMarkerServiceFactory = require('../../../../test/_mocks/resumeMarkerService.mock.factory') describe('consume-and-process-service', function () { describe('', function() { beforeEach(function () { var mockResumeMarkerService = resumeMarkerServiceFactory mock('../../../../lib/services/resume-marker-service', mockResumeMarkerService) service = mock.reRequire('../../../../lib/services/consume-and-process-service') }) afterEach(function(){ mock.stopAll() }) it('is available', function() { expect(service).not.toBe(undefined) }) it('does what its supposed to', function(done) { var instance = service({}) var numTimesConsumeHappened = 0 var MAX_CONSUME_COUNT = Math.max(1, Math.floor(Math.random() * 10)) var consumeFunc = (record, queue, cb) => { // // imagine we get some records from somewhere. var arrayOfRecords = [{id: 1, val: 'one'}, {id: 2, val: 'two'}, {id: 3, val: 'three'}] // then imagine we push the records on the queue queue.enqueue(arrayOfRecords) // decide what to tell our callback function var exitCondition = ++numTimesConsumeHappened >= MAX_CONSUME_COUNT var rtn if (exitCondition) rtn = 'cp_exit' else rtn = 'cp_process' // exit by calling the supplied callback cb(null, rtn, arrayOfRecords[arrayOfRecords.length - 1]) } var processFunc = (targetTimeInMillis, queue, nextTradeIdFunc, cb) => { var arrayOfRecords = queue.dequeue() var exitConditionReached = false var lastProcessedIndex = 0 // process the records somehow arrayOfRecords.forEach((/*r*/) => { /* do something */ /* set var if this record passed our targetTimeInMillis */ /* remember the most recently processed record, so we can pass it back */ }) if (exitConditionReached) cb(null, true, arrayOfRecords[lastProcessedIndex].trade_id) else cb(null, false, arrayOfRecords[arrayOfRecords.length - 1].trade_id) } instance.setOnConsumeFunc(consumeFunc) instance.setOnProcessFunc(processFunc) var targetTimeInMillis = new Date().getTime() - 10000 instance.go(targetTimeInMillis).then((finalRecord) => { expect(finalRecord).toBeDefined() expect(finalRecord.id).toBe(3) expect(finalRecord.val).toBe('three') expect(numTimesConsumeHappened).toEqual(MAX_CONSUME_COUNT) done() }) }) }) }) ================================================ FILE: test/_specs/lib/services/exchange-service.test.js ================================================ var service = require('../../../../lib/services/exchange-service') describe('Exchange Service', function() { var normalizedSelector = 'stub.BTC-USD' var exchangeId = '_stub' describe('', function() { var normalizedSelector = 'stub.BTC-USD' it('returns undefined the expected exchange when no parameter is passed in', function() { var instance = service({selector: normalizedSelector}) var rtn = instance.getExchange() expect(rtn).not.toBeDefined() }) }) describe('', function() { var selectorObject = {normalized: normalizedSelector, exchange_id: exchangeId } it('is available', function() { expect(service).not.toBe(undefined) }), it(' returns the expected exchange when no parameter is passed in', function() { var instance = service({selector: selectorObject}) var rtn = instance.getExchange() expect(rtn).toBeDefined() expect(rtn.getName()).toBe('stub') }) it(' returns the expected selector ', function() { var instance = service({selector: selectorObject}) var rtn = instance.getSelector() expect(rtn).toBeDefined() expect(rtn.normalized).toBe(selectorObject.normalized) expect(rtn.exchangeId).toBe(selectorObject.exchangeId) }) it(' has the correct values for backward and forward constants ', function() { var instance = service({selector: selectorObject}) expect(instance.BACKWARD).toBe('backward') expect(instance.FORWARD).toBe('forward') }) }) describe('when direction is backward ', function () { it('returns true when given time is less than targetTime and exchange direction is backward ', function() { var instance = service({selector: {normalized: normalizedSelector, exchange_id: exchangeId }}) expect(instance.isTimeSufficientlyLongAgo(500, 1000)).toBe(true) }) it('returns false when given time is greater than targetTime and exchange direction is backward ', function() { var instance = service({selector: {normalized: normalizedSelector, exchange_id: exchangeId }}) expect(instance.isTimeSufficientlyLongAgo(1000, 500)).toBe(false) }) }) describe(' when direction is forward ', function () { it(' returns false when given time is less than targetTime and exchange direction is forward ', function() { var instance = service({selector: {normalized: normalizedSelector, exchange_id: exchangeId }, historyScan: 'forward'}) expect(instance.isTimeSufficientlyLongAgo(500, 1000)).toBe(false) }) it(' returns true when given time is greater than targetTime and exchange direction is forward ', function() { var instance = service({selector: {normalized: normalizedSelector, exchange_id: exchangeId }, historyScan: 'forward'}) expect(instance.isTimeSufficientlyLongAgo(1000, 500)).toBe(true) }) }) }) ================================================ FILE: test/_specs/lib/services/resume-marker-service.test.js ================================================ var mock = require('mock-require') var service = require('../../../../lib/services/resume-marker-service') var collectionServiceFactory = require('../../../../test/_mocks/collectionService.mock.factory') describe('Resume Marker Service', function() { beforeEach(function() { mock('../../../../lib/services/collection-service', collectionServiceFactory) service = mock.reRequire('../../../../lib/services/resume-marker-service') }) describe('', function() { var conf = {selector: {normalized: 'tests.BTC-USD'}} it('is available', function() { var instance = service({}) expect(instance).toBeDefined() }) it('starts with zero ranges', function() { var instance = service(conf) expect(instance.getRanges().length).toBe(0) }) it('sets an id and _id attribute on a newly created range', function() { var instance = service(conf) instance.createNewRange({trade_id:3000, time:1517787104900}) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].id).toBeDefined expect(instance.getRanges()[0]._id).toBeDefined }) it('has one range, after creating a range, and it only contains the trade_id we just gave it', function() { var instance = service(conf) instance.createNewRange({trade_id:3000, time:1517787104900}) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) }) it('gets the correct range, when you create a range and then ask is that id in a range', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var rtn = instance.isWithinRange(trade) expect(rtn).toBeDefined() expect(rtn.from).toBe(3000) expect(rtn.oldest_time).toBe(1517787104900) }) it('returns true when we create a range on XXX, then ask is XXX + 1 within one of any range', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var trade2 = {trade_id:3001, time:1517787104902} var rtn = instance.isWithinOneOfAnyRange(trade2) expect(rtn).toBeDefined() expect(rtn.from).toBe(3000) expect(rtn.oldest_time).toBe(1517787104900) }) it('returns false when we create a range on XXX, then ask is XXX + 2 within one of any range', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var trade2 = {trade_id:3002, time:1517787104904} var rtn = instance.isWithinOneOfAnyRange(trade2) expect(rtn).not.toBeDefined() }) it('extends a range', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var trade2 = {trade_id:2999, time:1517787104898} instance.extendARange(trade2) expect(instance.getRanges()[0].from).toBe(2999) }) it('merges two now-adjacent ranges', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) expect(instance.getRanges().length).toBe(1) var trade2 = {trade_id:2998, time:1517787104894} instance.createNewRange(trade2) expect(instance.getRanges().length).toBe(2) instance.extendARange({trade_id:2999, time:1517787104896}) expect(instance.getRanges().length).toBe(2) instance.merge() expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(2998) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104894) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) }) it('pings correctly', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} var rtn = instance.ping(trade) expect(rtn).toBe(3000) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) var trade2 = {trade_id:2999, time:1517787104896} rtn = instance.ping(trade2) expect(rtn).toBe(2999) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(2999) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104896) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) // TODO: Test what happens if you give the same number. It should return that to you as the farthest so far. var trade3 = {trade_id:2998, time:1517787104894} rtn = instance.ping(trade3) expect(rtn).toBe(2998) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(2998) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104894) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) // break from happy path -- skip the next sequential record, should start a new range //var trade4 = {trade_id:2997, time:1517787104892}; var trade4 = {trade_id:2996, time:1517787104890} rtn = instance.ping(trade4) expect(rtn).toBe(2996) expect(instance.getRanges().length).toBe(2) expect(instance.getRanges()[0].from).toBe(2998) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104894) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) expect(instance.getRanges()[1].from).toBe(2996) expect(instance.getRanges()[1].to).toBe(2996) expect(instance.getRanges()[1].oldest_time).toBe(1517787104890) expect(instance.getRanges()[1].newest_time).toBe(1517787104890) var trade5 = {trade_id:2995, time:1517787104888} rtn = instance.ping(trade5) expect(rtn).toBe(2995) expect(instance.getRanges().length).toBe(2) expect(instance.getRanges()[0].from).toBe(2998) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104894) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) expect(instance.getRanges()[1].from).toBe(2995) expect(instance.getRanges()[1].to).toBe(2996) expect(instance.getRanges()[1].oldest_time).toBe(1517787104888) expect(instance.getRanges()[1].newest_time).toBe(1517787104890) // now, throw some salt in the game, ping the record we skipped earlier var trade6 = {trade_id:2997, time:1517787104892} rtn = instance.ping(trade6) expect(rtn).toBe(2995) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(2995) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104888) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) expect(instance.getPingCount()).toBe(6) }) }) describe('when forward', function() { var conf = {selector:{normalized: 'tests.BTC-USD'} } it('starts with zero ranges', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object expect(instance.getRanges().length).toBe(0) }) it('has one range, after creating a range, and it only contains the trade_id we just gave it', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object instance.createNewRange({trade_id:3000, time:1517787104900}) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) }) it('gets the correct range, when you create a range and then ask is that id in a range', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var rtn = instance.isWithinRange(trade) expect(rtn).toBeDefined() expect(rtn.from).toBe(3000) expect(rtn.oldest_time).toBe(1517787104900) }) it('returns true when we create a range on XXX, then ask is XXX + 1 within one of any range', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var trade2 = {trade_id:3001, time:1517787104902} var rtn = instance.isWithinOneOfAnyRange(trade2) expect(rtn).toBeDefined() expect(rtn.from).toBe(3000) expect(rtn.oldest_time).toBe(1517787104900) }) it('returns false when we create a range on XXX, then ask is XXX + 2 within one of any range', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:3000, time:1517787104900} instance.createNewRange(trade) var trade2 = {trade_id:3002, time:1517787104902} var rtn = instance.isWithinOneOfAnyRange(trade2) expect(rtn).not.toBeDefined() }) it('extends a range', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:2999, time:1517787104898} instance.createNewRange(trade) var trade2 = {trade_id:3000, time:1517787104900} instance.extendARange(trade2) expect(instance.getRanges()[0].from).toBe(2999) expect(instance.getRanges()[0].to).toBe(3000) }) it('merges two now-adjacent ranges', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:2998, time:1517787104894} instance.createNewRange(trade) expect(instance.getRanges().length).toBe(1) var trade2 = {trade_id:3000, time:1517787104900} instance.createNewRange(trade2) expect(instance.getRanges().length).toBe(2) instance.extendARange({trade_id:2999, time:1517787104896}) expect(instance.getRanges().length).toBe(2) instance.merge() expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(2998) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104894) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) }) it('pings correctly', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:3000, time:1517787104900} var rtn = instance.ping(trade) expect(rtn).toBe(3000) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3000) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104900) var trade2 = {trade_id:3001, time:1517787104902} rtn = instance.ping(trade2) expect(rtn).toBe(3001) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3001) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104902) // TODO: Test what happens if you give the same number. It should return that to you as the farthest so far. var trade3 = {trade_id:3002, time:1517787104904} rtn = instance.ping(trade3) expect(rtn).toBe(3002) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3002) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104904) // break from happy path -- skip the next sequential record, should start a new range //var trade4 = {trade_id:3004, time:1517787104906}; var trade4 = {trade_id:3004, time:1517787104906} rtn = instance.ping(trade4) expect(rtn).toBe(3004) expect(instance.getRanges().length).toBe(2) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3002) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104904) expect(instance.getRanges()[1].from).toBe(3004) expect(instance.getRanges()[1].to).toBe(3004) expect(instance.getRanges()[1].oldest_time).toBe(1517787104906) expect(instance.getRanges()[1].newest_time).toBe(1517787104906) var trade5 = {trade_id:3005, time:1517787104908} rtn = instance.ping(trade5) expect(rtn).toBe(3005) expect(instance.getRanges().length).toBe(2) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3002) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104904) expect(instance.getRanges()[1].from).toBe(3004) expect(instance.getRanges()[1].to).toBe(3005) expect(instance.getRanges()[1].oldest_time).toBe(1517787104906) expect(instance.getRanges()[1].newest_time).toBe(1517787104908) // now, throw some salt in the game, ping the record we skipped earlier var trade6 = {trade_id:3003, time:1517787104905} rtn = instance.ping(trade6) expect(rtn).toBe(3005) expect(instance.getRanges().length).toBe(1) expect(instance.getRanges()[0].from).toBe(3000) expect(instance.getRanges()[0].to).toBe(3005) expect(instance.getRanges()[0].oldest_time).toBe(1517787104900) expect(instance.getRanges()[0].newest_time).toBe(1517787104908) }) }) describe('database stuff', function() { var conf = {selector: {normalized: 'tests.BTC-USD'}, resumeMarkersArray: []} it('still calls the callback when flush is called and there are no ranges', function() { var instance = service(conf) instance.load() expect(instance.getRanges().length).toBe(0) var cb = jasmine.createSpy('flushCallback') instance.flush(cb) expect(cb).toHaveBeenCalled() }) }) describe('database stuff', function() { var conf = { selector: {normalized: 'tests.BTC-USD'}, resumeMarkersArray: [ {from: 2994, to: 2998, oldest_time: 1517787104960, newest_time: 1517787104986}, {from: 2894, to: 2898, oldest_time: 1517787103960, newest_time: 1517787103986}, {from: 2794, to: 2798, oldest_time: 1517787102960, newest_time: 1517787102986} ], mockDeleteManyFunction: jasmine.createSpy('mockDeleteManyFunction'), mockInsertManyFunction: jasmine.createSpy('mockInsertManyFunction') } it('loads records from the database correctly', function() { var instance = service(conf) instance.load() expect(instance.getRanges().length).toBe(3) }) it('writes changed records correctly', function() { var instance = service(conf) instance.load() var range = instance.getRanges()[0] range.from -= 1 instance.flush() expect(conf.mockDeleteManyFunction).toHaveBeenCalled() expect(conf.mockInsertManyFunction).toHaveBeenCalled() }) }) describe('ping count', function() { var conf = {selector: {normalized: 'tests.BTC-USD'}} it('increases, but not when a number is already in range', function() { var instance = service(conf) var trade = {trade_id:3000, time:1517787104900} instance.ping(trade) var trade2 = {trade_id:2999, time:1517787104896} instance.ping(trade2) // this should already be in range instance.ping(trade) expect(instance.getPingCount()).toBe(2) }) it('increases when direction is FORWARD, but not when a number is already in range', function() { var instance = service(conf) instance.setDirection('forward') // TODO: put this in a constants object var trade = {trade_id:2999, time:1517787104900} instance.ping(trade) var trade2 = {trade_id:3000, time:1517787104896} instance.ping(trade2) // this should already be in range instance.ping(trade) expect(instance.getPingCount()).toBe(2) }) }) }) ================================================ FILE: test/_specs/lib/services/trades-service.test.js ================================================ var mock = require('mock-require') var service = require('../../../../lib/services/trades-service') var exchangeServiceFactory = require('../../../../test/_mocks/exchangeService.mock.factory') var collectionServiceFactory = require('../../../../test/_mocks/collectionService.mock.factory') describe('Trades Service', function() { beforeEach(function() { mock('../../../../lib/services/exchange-service', exchangeServiceFactory) mock('../../../../lib/services/collection-service', collectionServiceFactory) service = mock.reRequire('../../../../lib/services/trades-service') }) afterEach(function() { mock.stopAll() }) describe('when exchange is backward, ', function() { it('is available', function() { expect(service).not.toBe(undefined) }) it('returns a valid opts object with default params', function() { var regex = new RegExp('/^stub.BTC-USD/') var instance = service({}) var rtn = instance.getInitialQueryAttributes() expect(rtn).toBeDefined() expect(rtn).toEqual({id: regex}) expect(rtn.trade_id).not.toBeDefined() expect(rtn.from).not.toBeDefined() expect(rtn.to).not.toBeDefined() }) it('returns a valid opts object when startingTradeId is given', function() { var regex = new RegExp('/^stub.BTC-USD/') var instance = service({direction:'backward'}) var rtn = instance.getInitialQueryAttributes(100) expect(rtn).toBeDefined() expect(rtn).toEqual({id: regex, trade_id: { $lt: 100}}) expect(rtn.from).not.toBeDefined() expect(rtn.to).not.toBeDefined() }) }) describe('when exchange is forward, ', function() { it('is available', function() { expect(service).not.toBe(undefined) }) it('returns a valid opts object with default params', function() { var regex = new RegExp('/^stub.BTC-USD/') var instance = service({direction:'forward'}) var rtn = instance.getInitialQueryAttributes() expect(rtn).toBeDefined() expect(rtn).toEqual({id: regex}) expect(rtn.trade_id).not.toBeDefined() expect(rtn.from).not.toBeDefined() expect(rtn.to).not.toBeDefined() }) it('returns a valid opts object when startingTradeId is given', function() { var regex = new RegExp('/^stub.BTC-USD/') var instance = service({direction:'forward'}) var rtn = instance.getInitialQueryAttributes(100) expect(rtn).toBeDefined() expect(rtn).toEqual({id: regex, trade_id: { $lt: 100}}) expect(rtn.from).not.toBeDefined() expect(rtn.to).not.toBeDefined() }) }) describe('getTrades when DB returns nothing, and API returns two trades', function() { it('calls getTrades correctly', function(done) { var instance = service({}) var normalizedSelector = exchangeServiceFactory({}).getSelector().normalized instance.getTrades().then((data) => { expect(data.length === 2).toBe(true) expect(data[0].id).toEqual(normalizedSelector + '-' + 3000) expect(data[1].id).toEqual(normalizedSelector + '-' + 3001) done() }) }) }) describe('getTrades when DB returns nothing, and API returns two trades', function() { it('creates two trades with valid zenbot metadata', function(done) { var instance = service({getTradesFunc: (/*opts, func*/) => { }, direction: 'forward'}) var normalizedSelector = exchangeServiceFactory({}).getSelector().normalized instance.getTrades().then((data) => { expect(data.length === 2).toBe(true) expect(data[0].id).toEqual(normalizedSelector + '-' + 3000) expect(data[0].selector).toEqual(normalizedSelector) expect(data[1].id).toEqual(normalizedSelector + '-' + 3001) expect(data[1].selector).toEqual(normalizedSelector) done() }) }) }) describe('getTrades when a tradeId is passed in, but the DB returns no results, and exchange is forward, and its history scan uses time', function() { var getTradesOptionsObservingFuncSpy = jasmine.createSpy('getTradesOptionsObservingFunc') var mockFindOneFunction = jasmine.createSpy('mockFindOneFunction') it('calls the DB to get the trade which has the time which is then passed to the exchange, and returns two valid zenbot trades', function(done) { var conf = { historyScanUsesTime: true, direction: 'forward', getTradesOptionsObservingFunc: getTradesOptionsObservingFuncSpy, tradesArray: [], exchangeTradesArray: [{trade_id: 3000, time: 99994}, {trade_id: 3001, time: 99992}], findOneReturnTrade: {id: 'stub.BTC-USD-3000', trade_id: 3000, time: 99992 }, mockFindOneFunction: mockFindOneFunction } var instance = service(conf) var normalizedSelector = exchangeServiceFactory(conf).getSelector().normalized instance.getTrades(3000).then((data) => { expect(getTradesOptionsObservingFuncSpy).toHaveBeenCalledWith({product_id: 'BTC-USD', from: 99992}) expect(mockFindOneFunction).toHaveBeenCalledWith({id: 'stub.BTC-USD-3000'}) expect(data.length === 2).toBe(true) expect(data[0].id).toEqual(normalizedSelector + '-' + 3000) expect(data[0].selector).toEqual(normalizedSelector) expect(data[1].id).toEqual(normalizedSelector + '-' + 3001) expect(data[1].selector).toEqual(normalizedSelector) done() }) }) }) describe('getTrades when DB returns two trades, and API returns no trades', function() { it('returns our two existing trades with valid zenbot metadata', function(done) { var instance = service({getTradesFunc: (/*opts, func*/) => { }, direction: 'forward'}) var normalizedSelector = exchangeServiceFactory({}).getSelector().normalized instance.getTrades().then((data) => { expect(data.length === 2).toBe(true) expect(data[0].id).toEqual(normalizedSelector + '-' + 3000) expect(data[0].selector).toEqual(normalizedSelector) expect(data[1].id).toEqual(normalizedSelector + '-' + 3001) expect(data[1].selector).toEqual(normalizedSelector) done() }) }) }) }) ================================================ FILE: test/lib/engine.test.js ================================================ var EventEmitter = require('events') describe('Engine', function() { describe('executeSignal', function() { describe('when maker in live mode', function(){ describe('with deposit set', function(){ it('and no held assets should use raw deposit', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = 0.25 var order_type = 'maker' var held_asset = 0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '1.38750138' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets should use adjusted deposit', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = 0.25 var order_type = 'maker' var held_asset = 0.25 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '1.23487623' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets so large adjusted deposit is below order minimum should not place order', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = 0.25 var order_type = 'maker' var held_asset = 2.0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert expect(buy_spy).not.toHaveBeenCalled() }) }) describe('with no deposit set', function(){ it('and no held assets should use raw buy_pct', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = undefined var order_type = 'maker' var held_asset = 0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '5.55000555' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) // no longer taking held assets into account with no buy_max /* it('and held assets should use adjusted buy_pct', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = undefined var order_type = 'maker' var held_asset = 0.5 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '4.93950000' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets so large adjusted buy_pct is below order minimum should not place order', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = undefined var order_type = 'maker' var held_asset = 10.25 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert expect(buy_spy).not.toHaveBeenCalled() }) */ }) }) describe('when taker in live mode', function(){ describe('with deposit set',function(){ it('and no held assets should use raw deposit', function(){ // arrange var signal_type = 'buy' var currency_amount = 1 var buy_pct = 50 var deposit = 0.25 var order_type = 'taker' var held_asset = 0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '1.38611665' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets should use adjusted deposit', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = 0.25 var order_type = 'taker' var held_asset = 0.25 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '1.23364382' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets so large adjusted deposit is below order minimum should not place order', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = 0.25 var order_type = 'taker' var held_asset = 2.0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert expect(buy_spy).not.toHaveBeenCalled() }) }) describe('with no deposit set',function(){ it('with no deposit set and no held assets should use raw buy_pct', function(){ // arrange var signal_type = 'buy' var currency_amount = 1 var buy_pct = 50 var deposit = undefined var order_type = 'taker' var held_asset = 0 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '5.54446662' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) /* it('and held assets should use adjusted buy_pct', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = undefined var order_type = 'taker' var held_asset = 0.5 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert var expected = '4.93455555' var buyArgs = buy_spy.calls.mostRecent().args[0] expect(buyArgs.size).toBe(expected) }) it('and held assets so large adjusted buy_pct is below order minimum should not place order', function(){ // arrange var signal_type = 'buy' var currency_amount = 1.0 var buy_pct = 50 var deposit = undefined var order_type = 'taker' var held_asset = 5.25 var buy_spy = jasmine.createSpy('buy') var sut = createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy) // act sut.executeSignal(signal_type) // assert expect(buy_spy).not.toHaveBeenCalled() }) */ }) }) }) }) var mock = require('mock-require') var path = require('path') function createEngine(currency_amount, buy_pct, deposit, order_type, held_asset, buy_spy){ var fake_asset = 'test_asset' var fake_currency = 'BTC' var fake_exchange = 'test_exchange' var fake_project = 'test_product' var fake_bid = 0.10 var fake_ask = 0.11 var fake_balance = { currency: currency_amount, asset: held_asset } var fake_product = { 'asset': fake_asset, 'currency': fake_currency, 'min_total': '0.1', 'max_size': null, 'increment': '0.01', 'label': 'Test TST/BTC' } var fake_return = { 'conf': { eventBus: new EventEmitter(), output: { api: {} } }, 'exchanges.test_exchange' : function() { return { getProducts: function() { return [fake_product] }, getQuote: function(product, callback){ callback(null, { bid: fake_bid, ask: fake_ask}) }, getBalance: function(args, callback){ return callback(null, fake_balance)}, buy: buy_spy, name: fake_exchange, makerFee: 0.1, takerFee: 0.2 } }, 'lib.notify': { pushMessage: function(/*title, message*/){ } } } var exchange_path = path.resolve(__dirname, '../../extensions/exchanges/test_exchange/exchange') mock(exchange_path, fake_return['exchanges.test_exchange']) mock('./notify', fake_return['lib.notify']) var input = { options: { selector: { exchange_id:fake_exchange, product_id:fake_project, asset:fake_asset, currency: fake_currency }, period: '30m', markdown_buy_pct : 2, mode:'live', order_type: order_type, buy_pct:buy_pct, deposit:deposit } } var engine = require('../../lib/engine') return engine(input, fake_return['conf']) } ================================================ FILE: test/lib/format.test.js ================================================ let { formatAsset, formatCurrency, formatPercent } = require('../../lib/format') describe('Format', () => { describe('formatAsset', () => { it('formats assets as expected', () => { expect(formatAsset(5, 'USD')).toBe('5.00000000 USD') }) }) describe('formatCurrency', () => { it('formats currency as expected', () => { expect(formatCurrency(1000, 'USD')).toBe('1000.00 USD') expect(formatCurrency(100, 'THING')).toBe('100.000 THING') expect(formatCurrency(1, 'GBP')).toBe('1.00000 GBP') expect(formatCurrency(0.008, 'XRP')).toBe('0.00800000 XRP') expect(formatCurrency(10, 'USD', true)).toBe('10.0000') expect(formatCurrency(10, 'USD', false, false, true)).toBe('10.0000 USD') }) }) describe('formatPercent', () => { it('formats percentages as expected', () => { expect(formatPercent(0.1)).toBe('+10.00%') expect(formatPercent(-0.03)).toBe('-3.00%') expect(formatPercent(0.0005)).toBe('+0.05%') }) }) }) ================================================ FILE: test/lib/rsi.test.js ================================================ var RSI = require('../../lib/rsi') describe('RSI (Relative Strength Index)', function () { it('should calculate RSI with default period', function () { RSI(normalData, 'rsi', 14) expect(normalData.period.rsi).toEqual(32.26) }) it('should set RSI to 100 when there is no losses for the entire period', function() { RSI(noLossData, 'rsi', 14) expect(noLossData.period.rsi).toEqual(100) }) it('should set RSI to 0 when there is no gains for the entire period', function() { RSI(noGainData, 'rsi', 14) expect(noGainData.period.rsi).toEqual(0) }) it('should set RSI to 0 when there is no price change for the entire period', function() { RSI(noPriceChangeData, 'rsi', 14) expect(noPriceChangeData.period.rsi).toEqual(100) }) }) var normalData = { lookback: [ {close: 46.28}, {close: 46.00}, {close: 46.03}, {close: 46.41}, {close: 46.22}, {close: 45.64}, {close: 46.21}, {close: 46.25}, {close: 45.71}, {close: 46.45}, {close: 45.78}, {close: 45.35}, {close: 44.03}, {close: 44.18}, {close: 44.22}, {close: 44.57}, {close: 43.42}, {close: 42.66}, {close: 43.13} ], period: {} } var noLossData = { lookback: [ {close: 46.08}, {close: 46.18}, {close: 46.28}, {close: 46.38}, {close: 46.48}, {close: 46.58}, {close: 46.68}, {close: 46.78}, {close: 46.88}, {close: 46.98}, {close: 47.08}, {close: 47.18}, {close: 47.28}, {close: 47.38}, {close: 47.48}, {close: 47.58}, {close: 47.68}, {close: 47.78}, {close: 47.88} ], period: {} } var noGainData = { lookback: noLossData.lookback.slice(0).reverse(), period: {} } var noPriceChangeData = { lookback: [ {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8}, {close: 46.8} ], period: {} } ================================================ FILE: test/lib/srsi.test.js ================================================ var SRSI = require('../../lib/srsi') describe('SRSI (StochRSI Oscillator)', function () { it('should calculate SRSI with default period', function () { SRSI(data, 'srsi', 14, 3, 3) expect(data.period.srsi_K).toEqual(19.38) expect(data.period.srsi_D).toEqual(23.18) }) }) var data = { lookback: [ {rsi: 64.38}, {rsi: 66.71}, {rsi: 70.29}, {rsi: 66.49}, {rsi: 71.47}, {rsi: 76.17}, {rsi: 83.66}, {rsi: 81.85}, {rsi: 82.55}, {rsi: 82.89}, {rsi: 78.60}, {rsi: 64.78}, {rsi: 64.77}, {rsi: 70.05}, {rsi: 68.76}, {rsi: 69.53}, {rsi: 70.15} ].reverse(), period: { rsi: 65.61 } } ================================================ FILE: update.bat ================================================ REM git checkout package.json package-lock.json REM git pull rd /q /s node_modules npm install && npm update && npm dedupe ================================================ FILE: update.sh ================================================ #!/bin/bash # the below will work assuming no other custom modifications have been made. rm -rf node_modules/ git checkout package.json package-lock.json git pull npm install && npm update && npm dedupe ================================================ FILE: webpack-src/js/app.js ================================================ // Import Bootstrap import 'bootstrap' import 'bootstrap/dist/css/bootstrap.min.css' import 'counterup/jquery.counterup.js' import 'waypoints/lib/jquery.waypoints.min.js' import '../../templates/dashboard_assets/js/custom.js' import '../../templates/dashboard_assets/js/jquery.slimscroll.js' import '../../templates/dashboard_assets/css/style.css' import '../../templates/dashboard_assets/css/spinners.css' import '../../templates/dashboard_assets/css/animate.css' import '../../templates/dashboard_assets/css/colors/default.css' ================================================ FILE: webpack-src/js/echarts.js ================================================ var echarts = require('echarts/lib/echarts') require('echarts/lib/chart/line') require('echarts/lib/chart/bar') require('echarts/lib/chart/candlestick') require('echarts/lib/chart/scatter') require('echarts/lib/component/tooltip') require('echarts/lib/component/dataZoom') require('echarts/lib/component/markPoint') require('echarts/lib/component/toolbox') module.exports = echarts ================================================ FILE: webpack.config.js ================================================ 'use strict' const path = require('path') const webpack = require('webpack') const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { entry: { app: './webpack-src/js/app.js', echarts: './webpack-src/js/echarts.js' }, optimization: { minimize: true }, plugins: [ new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery', Popper: ['popper.js', 'default'], }), new MiniCssExtractPlugin({ filename: '[name].bundle.css' }) ], output: { publicPath: '/assets-wp/', path: path.join(__dirname, '/dist/'), filename: '[name].bundle.js' }, module: { rules: [ { test: /\.js$/, loader: 'babel-loader', exclude: /(node_modules)/, options: { presets: ['env'] } }, { test: /\.(scss)$/, use: [{ loader: 'style-loader', // inject CSS to page }, { loader: 'css-loader', // translates CSS into CommonJS modules }, { loader: 'postcss-loader', // Run post css actions options: { plugins: function () { // post css plugins, can be exported to postcss.config.js return [ require('precss'), require('autoprefixer') ] } } }, { loader: 'sass-loader' // compiles SASS to CSS }] }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' }, { test: /\.(woff|woff2)$/, use: ['url-loader', { options: { limit: 5000 } } ] }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader', options: { limit: 10000, mimetype: 'application/octet-stream' } }] }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'url-loader', options: { limit: 10000, mimetype: 'image/svg+xml' } }] }, { test: require.resolve('jquery'), use: [{ loader: 'expose-loader', options: { exposes: ['$','jQuery'] } }] }, { test: require.resolve('./webpack-src/js/echarts.js'), use: [{ loader: 'expose-loader', options: { exposes: ['echarts'] } }] } ], }, } ================================================ FILE: zenbot.bat ================================================ node zenbot.js %* ================================================ FILE: zenbot.js ================================================ var semver = require('semver') var path = require('path') var program = require('commander') program._name = 'zenbot' var versions = process.versions if (semver.gt('8.3.0', versions.node)) { console.log('You are running a node.js version older than 8.3.x, please upgrade via https://nodejs.org/en/') process.exit(1) } var fs = require('fs') , boot = require('./boot') boot(function (err, zenbot) { if (err) { throw err } program.version(zenbot.version) var command_directory = './commands' fs.readdir(command_directory, function(err, files){ if (err) { throw err } var commands = files.map((file)=>{ return path.join(command_directory, file) }).filter((file)=>{ return fs.statSync(file).isFile() }) commands.forEach((file)=>{ require(path.resolve(__dirname, file.replace('.js','')))(program, zenbot.conf) }) program .command('*', 'Display help', { noHelp: true }) .action((cmd)=>{ console.log('Invalid command: ' + cmd) program.help() }) program.parse(process.argv) }) }) ================================================ FILE: zenbot.sh ================================================ #!/bin/sh env node zenbot.js $@