From 89562094b7529a8ad7ad6fbd7580234508f794eb Mon Sep 17 00:00:00 2001 From: lychiyu Date: Fri, 30 Aug 2024 22:55:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BB=93=E5=BA=93?= =?UTF-8?q?=EF=BC=8Cb87213827e08344908cdd718039f3120d047b44e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 7 + .env.local.example | 13 + .evans.toml | 3 + .gitattributes | 0 .gitignore | 68 + .golangci.yml | 9 + .markdownlint.yaml | 5 + .pre-commit-config.yaml | 14 + CLA.md | 29 + CODEOWNERS | 2 + CODE_OF_CONDUCT.md | 127 + CONTRIBUTING.md | 80 + Dockerfile | 33 + LICENSE | 661 + Makefile | 277 + Procfile | 1 + README.md | 667 + README.zh_TW.md | 624 + app.json | 26 + apps/backtest-report/.eslintrc.json | 3 + apps/backtest-report/.gitignore | 35 + apps/backtest-report/README.md | 54 + .../components/OrderListTable.tsx | 81 + .../components/ReportDetails.tsx | 248 + .../components/ReportNavigator.tsx | 79 + .../TimeRangeSlider/components/Handle.js | 44 + .../components/KeyboardHandle.js | 32 + .../TimeRangeSlider/components/SliderRail.js | 13 + .../TimeRangeSlider/components/Tick.js | 41 + .../TimeRangeSlider/components/Track.js | 52 + .../components/TimeRangeSlider/index.jsx | 256 + .../components/TimeRangeSlider/index.scss | 126 + .../components/TradingViewChart.tsx | 709 + apps/backtest-report/next-env.d.ts | 5 + apps/backtest-report/next.config.js | 33 + apps/backtest-report/package.json | 42 + apps/backtest-report/pages/_app.tsx | 28 + apps/backtest-report/pages/_document.tsx | 44 + apps/backtest-report/pages/api/hello.ts | 13 + apps/backtest-report/pages/index.tsx | 51 + apps/backtest-report/public/favicon.ico | Bin 0 -> 25931 bytes apps/backtest-report/public/vercel.svg | 4 + apps/backtest-report/src/Chart.js | 131 + apps/backtest-report/src/utils.js | 3 + apps/backtest-report/styles/Home.module.css | 78 + apps/backtest-report/styles/globals.css | 16 + apps/backtest-report/tsconfig.json | 20 + apps/backtest-report/types/index.ts | 3 + apps/backtest-report/types/market.ts | 16 + apps/backtest-report/types/order.ts | 15 + apps/backtest-report/types/report.ts | 76 + apps/backtest-report/yarn.lock | 2483 +++ apps/frontend/.gitignore | 34 + apps/frontend/.prettierignore | 3 + apps/frontend/.prettierrc.json | 3 + apps/frontend/README.md | 34 + apps/frontend/api/bbgo.ts | 190 + .../components/AddExchangeSessionForm.js | 342 + .../components/ConfigureDatabaseForm.js | 209 + .../components/ConfigureGridStrategyForm.js | 446 + apps/frontend/components/ConnectWallet.js | 143 + apps/frontend/components/Detail.tsx | 56 + .../components/ExchangeSessionTabPanel.js | 49 + apps/frontend/components/ReviewSessions.js | 88 + apps/frontend/components/ReviewStrategies.js | 157 + apps/frontend/components/RunningTime.tsx | 34 + .../components/SaveConfigAndRestart.js | 105 + apps/frontend/components/SideBar.js | 103 + apps/frontend/components/Stats.tsx | 51 + apps/frontend/components/Summary.tsx | 50 + apps/frontend/components/SyncButton.tsx | 39 + .../frontend/components/TotalAssetsDetails.js | 87 + apps/frontend/components/TotalAssetsPie.js | 94 + .../frontend/components/TotalAssetsSummary.js | 60 + apps/frontend/components/TradingVolumeBar.js | 161 + .../frontend/components/TradingVolumePanel.js | 72 + apps/frontend/hooks/useInterval.ts | 20 + apps/frontend/layouts/DashboardLayout.js | 65 + apps/frontend/layouts/PlainLayout.js | 43 + apps/frontend/next-env.d.ts | 5 + apps/frontend/next.config.js | 9 + apps/frontend/package.json | 42 + apps/frontend/pages/_app.tsx | 43 + apps/frontend/pages/_document.js | 72 + apps/frontend/pages/api/hello.js | 6 + apps/frontend/pages/connect/index.js | 55 + apps/frontend/pages/index.tsx | 121 + apps/frontend/pages/orders.js | 81 + apps/frontend/pages/setup/index.js | 132 + apps/frontend/pages/strategies.tsx | 43 + apps/frontend/pages/trades.js | 68 + apps/frontend/public/favicon.ico | Bin 0 -> 15086 bytes apps/frontend/public/images/bch-logo.svg | 18 + apps/frontend/public/images/bnb-logo.svg | 1 + apps/frontend/public/images/btc-logo.svg | 15 + apps/frontend/public/images/comp-logo.svg | 16 + apps/frontend/public/images/dai-logo.svg | 13 + apps/frontend/public/images/dot-logo.svg | 20 + apps/frontend/public/images/eth-logo.svg | 21 + apps/frontend/public/images/grt-logo.svg | 19 + apps/frontend/public/images/link-logo.svg | 1 + apps/frontend/public/images/ltc-logo.svg | 1 + apps/frontend/public/images/max-logo.svg | 1 + apps/frontend/public/images/snt-logo.svg | 1 + apps/frontend/public/images/sxp-logo.svg | 1 + apps/frontend/public/images/twd-logo.svg | 1 + apps/frontend/public/images/usdt-logo.svg | 1 + apps/frontend/public/images/xrp-logo.svg | 1 + apps/frontend/public/images/yfi-logo.svg | 1 + apps/frontend/public/vercel.svg | 4 + apps/frontend/src/theme.js | 24 + apps/frontend/src/utils.js | 37 + apps/frontend/styles/Home.module.css | 122 + apps/frontend/styles/globals.css | 16 + apps/frontend/tsconfig.json | 30 + apps/frontend/yarn.lock | 2240 ++ assets/bbg-256.png | Bin 0 -> 13535 bytes assets/bbg-32.png | Bin 0 -> 4592 bytes assets/bbg-512.png | Bin 0 -> 26982 bytes assets/overview.svg | 3 + assets/screenshots/backtest-report.jpg | Bin 0 -> 69289 bytes assets/screenshots/dashboard.jpeg | Bin 0 -> 51497 bytes assets/screenshots/setup-wizard-grid.jpeg | Bin 0 -> 29353 bytes assets/screenshots/setup-wizard.jpeg | Bin 0 -> 43494 bytes bbgo.sql | 212 + charts/bbgo/.helmignore | 23 + charts/bbgo/Chart.yaml | 23 + charts/bbgo/templates/NOTES.txt | 21 + charts/bbgo/templates/_helpers.tpl | 65 + charts/bbgo/templates/configmap.yaml | 18 + charts/bbgo/templates/cronjob_sync.yaml | 55 + charts/bbgo/templates/deployment.yaml | 137 + charts/bbgo/templates/hpa.yaml | 28 + charts/bbgo/templates/ingress.yaml | 41 + charts/bbgo/templates/podmonitor.yaml | 15 + charts/bbgo/templates/service.yaml | 21 + charts/bbgo/templates/serviceaccount.yaml | 12 + .../bbgo/templates/tests/test-connection.yaml | 15 + charts/bbgo/values.yaml | 127 + cmd/bbgo-lorca/main.go | 161 + cmd/bbgo-webview/main.go | 170 + cmd/bbgo/main.go | 9 + cmd/update-doc/main.go | 19 + codecov.yaml | 21 + codecov.yml | 23 + config/atrpin.yaml | 40 + config/audacitymaker.yaml | 21 + config/autoborrow.yaml | 38 + config/autobuy.yaml | 22 + config/backtest.yaml | 23 + config/binance-margin.yaml | 27 + config/bollgrid.yaml | 60 + config/bollmaker.yaml | 232 + config/bollmaker_optimizer.yaml | 29 + config/convert.yaml | 26 + config/dca.yaml | 23 + config/dca2.yaml | 31 + config/deposit2transfer.yaml | 12 + config/driftBTC.yaml | 141 + config/elliottwave.yaml | 126 + config/emacross.yaml | 37 + config/emastop.yaml | 31 + config/environment.yaml | 7 + config/etf.yaml | 11 + config/ewo_dgtrd.yaml | 65 + config/factorzoo.yaml | 44 + config/fixedmaker.yaml | 34 + config/flashcrash.yaml | 14 + config/fmaker.yaml | 26 + config/grid-usdttwd.yaml | 53 + config/grid.yaml | 61 + config/grid2-max.yaml | 94 + config/grid2.yaml | 128 + config/harmonic.yaml | 37 + config/irr.yaml | 40 + config/linregmaker.yaml | 186 + config/liquiditymaker.yaml | 54 + config/marketcap.yaml | 27 + config/max-margin.yaml | 35 + config/minimal.yaml | 10 + config/multi-session.yaml | 50 + config/optimizer-hyperparam-search.yaml | 52 + config/optimizer.yaml | 26 + config/pivotshort-GMTBUSD.yaml | 63 + config/pivotshort.yaml | 153 + config/pivotshort_optimizer.yaml | 65 + config/pricealert-tg.yaml | 12 + config/pricealert.yaml | 22 + config/pricedrop.yaml | 55 + config/random.yaml | 10 + config/rebalance.yaml | 17 + config/rsicross.yaml | 54 + config/rsmaker.yaml | 101 + config/schedule-USDTTWD.yaml | 33 + config/schedule-btcusdt.yaml | 30 + config/schedule-ethusdt.yaml | 83 + config/schedule.yaml | 33 + config/scmaker.yaml | 80 + config/skeleton.yaml | 24 + config/supertrend.yaml | 124 + config/support-margin.yaml | 70 + config/support.yaml | 56 + config/swing.yaml | 43 + config/sync.yaml | 64 + config/trendtrader.yaml | 50 + config/tri.yaml | 35 + config/wall.yaml | 46 + config/xalign.yaml | 49 + config/xbalance.yaml | 39 + config/xdepthmaker.yaml | 67 + config/xfixedmaker.yaml | 51 + config/xfunding.yaml | 64 + config/xgap.yaml | 41 + config/xmaker-btcusdt.yaml | 80 + config/xmaker-ethusdt.yaml | 82 + config/xmaker.yaml | 75 + config/xnav.yaml | 36 + config/xpuremaker.yaml | 28 + contracts/.eslintrc.js | 17 + contracts/.gitignore | 3 + contracts/.solhint.json | 8 + contracts/README.md | 51 + contracts/bsc-secret.json | 4 + contracts/contracts/Migrations.sol | 20 + contracts/contracts/Token.sol | 5 + .../child/ChildToken/ChildMintableERC20.sol | 79 + .../child/ChildToken/IChildToken.sol | 5 + .../contracts/common/AccessControlMixin.sol | 19 + contracts/contracts/common/ContextMixin.sol | 25 + contracts/contracts/common/EIP712Base.sol | 77 + contracts/contracts/common/Initializable.sol | 12 + .../common/NativeMetaTransaction.sol | 106 + .../contracts/common/Proxy/IERCProxy.sol | 7 + contracts/contracts/common/Proxy/Proxy.sol | 39 + .../common/Proxy/UpgradableProxy.sol | 103 + contracts/development-secret.json | 4 + contracts/flat/BBG.sol | 1433 ++ contracts/flat/ChildERC20.sol | 1509 ++ contracts/flat/ChildMintableERC20.sol | 1508 ++ contracts/hardhat.config.js | 11 + contracts/migrations/2_deploy_child_erc20.js | 5 + contracts/package-lock.json | 17541 ++++++++++++++++ contracts/package.json | 40 + contracts/polygon-secret.json | 4 + contracts/test/erc20.js | 16 + contracts/truffle-config.js | 133 + data/bbgo_test.sql | 3 + data/binance-markets.json | 1 + deploy.sh | 187 + desktop/build-darwin.sh | 23 + desktop/build-osx-info-plist.sh | 21 + desktop/icons/icon-256.png | Bin 0 -> 13535 bytes desktop/icons/icon.icns | Bin 0 -> 68220 bytes desktop/icons/icon.png | Bin 0 -> 26982 bytes doc/README.md | 34 + doc/build-from-source.md | 133 + doc/commands/bbgo.md | 61 + doc/commands/bbgo_account.md | 44 + doc/commands/bbgo_backtest.md | 53 + doc/commands/bbgo_balances.md | 43 + doc/commands/bbgo_build.md | 42 + doc/commands/bbgo_cancel-order.md | 52 + doc/commands/bbgo_deposits.md | 44 + doc/commands/bbgo_execute-order.md | 51 + doc/commands/bbgo_get-order.md | 45 + doc/commands/bbgo_hoptimize.md | 48 + doc/commands/bbgo_kline.md | 45 + doc/commands/bbgo_list-orders.md | 44 + doc/commands/bbgo_margin.md | 41 + doc/commands/bbgo_margin_interests.md | 44 + doc/commands/bbgo_margin_loans.md | 44 + doc/commands/bbgo_margin_repays.md | 44 + doc/commands/bbgo_market.md | 43 + doc/commands/bbgo_optimize.md | 47 + doc/commands/bbgo_orderbook.md | 45 + doc/commands/bbgo_orderupdate.md | 43 + doc/commands/bbgo_pnl.md | 52 + doc/commands/bbgo_run.md | 54 + doc/commands/bbgo_submit-order.md | 49 + doc/commands/bbgo_sync.md | 45 + doc/commands/bbgo_trades.md | 45 + doc/commands/bbgo_tradeupdate.md | 43 + doc/commands/bbgo_transfer-history.md | 45 + doc/commands/bbgo_userdatastream.md | 43 + doc/commands/bbgo_version.md | 42 + doc/configuration/envvars.md | 24 + doc/configuration/slack.md | 36 + doc/configuration/sync.md | 42 + doc/configuration/telegram.md | 55 + doc/deployment/helm-chart.md | 94 + doc/deployment/systemd.md | 42 + doc/development/adding-new-exchange.md | 229 + doc/development/frontend.md | 40 + doc/development/indicator-v1.md | 128 + doc/development/indicator.md | 211 + doc/development/kucoin-cli.md | 22 + doc/development/migration.md | 63 + doc/development/release-process.md | 50 + doc/development/series.md | 65 + doc/release/v1.19.3.md | 4 + doc/release/v1.19.4.md | 3 + doc/release/v1.20.0.md | 7 + doc/release/v1.21.0.md | 23 + doc/release/v1.21.1.md | 13 + doc/release/v1.21.2.md | 3 + doc/release/v1.21.3.md | 6 + doc/release/v1.21.4.md | 4 + doc/release/v1.22.0.md | 8 + doc/release/v1.22.1.md | 9 + doc/release/v1.22.2.md | 7 + doc/release/v1.22.3.md | 4 + doc/release/v1.23.0.md | 10 + doc/release/v1.24.0.md | 14 + doc/release/v1.25.0.md | 3 + doc/release/v1.25.1.md | 7 + doc/release/v1.25.2.md | 4 + doc/release/v1.25.3.md | 6 + doc/release/v1.25.4.md | 4 + doc/release/v1.26.0.md | 9 + doc/release/v1.26.1.md | 8 + doc/release/v1.26.3.md | 4 + doc/release/v1.28.0.md | 26 + doc/release/v1.29.0.md | 16 + doc/release/v1.30.0.md | 10 + doc/release/v1.30.1.md | 4 + doc/release/v1.30.2.md | 5 + doc/release/v1.30.3.md | 4 + doc/release/v1.31.0.md | 23 + doc/release/v1.31.1.md | 4 + doc/release/v1.31.2.md | 3 + doc/release/v1.31.3.md | 3 + doc/release/v1.31.4.md | 10 + doc/release/v1.32.0.md | 20 + doc/release/v1.33.0.md | 106 + doc/release/v1.33.1.md | 14 + doc/release/v1.33.2.md | 12 + doc/release/v1.33.3.md | 12 + doc/release/v1.33.4.md | 23 + doc/release/v1.34.0.md | 43 + doc/release/v1.35.0.md | 20 + doc/release/v1.36.0.md | 83 + doc/release/v1.37.0.md | 36 + doc/release/v1.38.0.md | 47 + doc/release/v1.39.0.md | 55 + doc/release/v1.39.1.md | 7 + doc/release/v1.39.2.md | 16 + doc/release/v1.40.1.md | 7 + doc/release/v1.40.2.md | 13 + doc/release/v1.40.3.md | 34 + doc/release/v1.40.4.md | 7 + doc/release/v1.41.0.md | 46 + doc/release/v1.42.0.md | 43 + doc/release/v1.43.0.md | 62 + doc/release/v1.43.1.md | 7 + doc/release/v1.44.0.md | 61 + doc/release/v1.44.1.md | 7 + doc/release/v1.45.0.md | 23 + doc/release/v1.46.0.md | 20 + doc/release/v1.47.0.md | 11 + doc/release/v1.48.0.md | 39 + doc/release/v1.48.1.md | 2 + doc/release/v1.48.2.md | 12 + doc/release/v1.48.3.md | 6 + doc/release/v1.48.4.md | 5 + doc/release/v1.49.0.md | 16 + doc/release/v1.50.0.md | 5 + doc/release/v1.50.1.md | 4 + doc/release/v1.51.0.md | 26 + doc/release/v1.51.1.md | 20 + doc/release/v1.52.0.md | 55 + doc/release/v1.53.0.md | 65 + doc/release/v1.54.0.md | 18 + doc/release/v1.55.0.md | 28 + doc/release/v1.55.1.md | 6 + doc/release/v1.55.2.md | 6 + doc/release/v1.55.3.md | 4 + doc/release/v1.55.4.md | 5 + doc/release/v1.56.0.md | 65 + doc/release/v1.56.1.md | 6 + doc/release/v1.56.2.md | 6 + doc/release/v1.57.0.md | 31 + doc/release/v1.58.0.md | 48 + doc/release/v1.59.0.md | 32 + doc/release/v1.59.1.md | 5 + doc/release/v1.59.2.md | 9 + doc/release/v1.60.0.md | 62 + doc/strategy/grid.md | 32 + doc/strategy/interaction.md | 32 + doc/strategy/marketcap.md | 28 + doc/strategy/pricealert.md | 25 + doc/strategy/rebalance.md | 31 + doc/strategy/supertrend.md | 51 + doc/strategy/support.md | 50 + doc/topics/back-testing.md | 81 + doc/topics/bbgo-completion.md | 70 + doc/topics/developing-strategy.md | 565 + doc/topics/dnum-binary.md | 26 + doc/topics/google-spreadsheet.md | 48 + doc/topics/grpc.md | 54 + doc/topics/riskcontrols.md | 92 + doc/topics/strategy-testing.md | 50 + doc/topics/twap.md | 39 + .../subscribe_book_kucoin.json | 10 + .../subscribe_kline_kucoin.json | 10 + evans/tradingService/submit_order_max.json | 13 + evans/userDataService/subscribe_binance.json | 3 + evans/userDataService/subscribe_kucoin.json | 3 + examples/exchange-api/binance-book/main.go | 108 + examples/exchange-api/binance-margin/main.go | 129 + examples/interact/main.go | 151 + examples/kucoin-accounts/main.go | 72 + examples/kucoin/accounts.go | 41 + examples/kucoin/bullet.go | 55 + examples/kucoin/fills.go | 45 + examples/kucoin/main.go | 65 + examples/kucoin/orderbook.go | 44 + examples/kucoin/orders.go | 221 + examples/kucoin/subaccounts.go | 31 + examples/kucoin/symbols.go | 27 + examples/kucoin/tickers.go | 47 + examples/kucoin/websocket.go | 155 + examples/max-rewards/main.go | 49 + examples/max-withdraw/main.go | 125 + examples/okex-book/main.go | 215 + examples/telebot/main.go | 154 + go.mod | 157 + go.sum | 1261 ++ linode/max-grid-usdttwd.sh | 99 + migrations/mysql/20200721225616_trades.sql | 42 + .../mysql/20200819054742_trade_index.sql | 5 + migrations/mysql/20201102222546_orders.sql | 35 + .../20201103173342_trades_add_order_id.sql | 5 + .../mysql/20201105092857_trades_index_fix.sql | 8 + .../mysql/20201105093056_orders_add_index.sql | 5 + migrations/mysql/20201106114742_klines.sql | 34 + .../20201211175751_fix_symbol_length.sql | 5 + .../mysql/20210118163847_fix_unique_index.sql | 9 + .../20210119232826_add_margin_columns.sql | 4 + ...10129182704_trade_price_quantity_index.sql | 10 + .../mysql/20210215203116_add_pnl_column.sql | 9 + .../20210223080622_add_rewards_table.sql | 32 + .../20210301140656_add_withdraws_table.sql | 28 + .../20210307201830_add_deposits_table.sql | 26 + .../20210416230730_klines_symbol_length.sql | 25 + .../20210421091430_increase_symbol_length.sql | 25 + ...20210421095030_increase_decimal_length.sql | 25 + ...0531234123_add_kline_taker_buy_columns.sql | 47 + .../20211205162043_add_is_futures_column.sql | 18 + .../mysql/20211211020303_add_ftx_kline.sql | 33 + ...20211211034819_add_nav_history_details.sql | 26 + ...11211103657_update_fee_currency_length.sql | 9 + .../20211226022411_add_kucoin_klines.sql | 10 + .../mysql/20220304153317_add_profit_table.sql | 71 + .../mysql/20220307132917_add_positions.sql | 30 + .../20220317125555_fix_trade_indexes.sql | 19 + .../mysql/20220419121046_fix_fee_column.sql | 21 + .../20220503144849_add_margin_info_to_nav.sql | 27 + .../20220504184155_fix_net_asset_column.sql | 19 + ...0220512170322_fix_profit_symbol_length.sql | 11 + .../mysql/20220520140707_kline_unique_idx.sql | 47 + .../mysql/20220531012226_margin_loans.sql | 24 + .../mysql/20220531013327_margin_repays.sql | 24 + .../mysql/20220531013542_margin_interests.sql | 24 + .../20220531015005_margin_liquidations.sql | 33 + .../mysql/20230815173104_add_bybit_klines.sql | 10 + ...20231123125402_fix_order_status_length.sql | 11 + .../mysql/20240531163411_trades_created.sql | 14 + migrations/sqlite3/20200721225616_trades.sql | 21 + .../sqlite3/20200819054742_trade_index.sql | 10 + migrations/sqlite3/20201102222546_orders.sql | 26 + .../20201103173342_trades_add_order_id.sql | 9 + .../20201105092857_trades_index_fix.sql | 19 + .../20201105093056_orders_add_index.sql | 7 + migrations/sqlite3/20201106114742_klines.sql | 98 + .../20210118163847_fix_unique_index.sql | 9 + .../20210119232826_add_margin_columns.sql | 33 + ...10129182704_trade_price_quantity_index.sql | 10 + .../sqlite3/20210215203111_add_pnl_column.sql | 18 + .../20210223080622_add_rewards_table.sql | 30 + .../20210301140656_add_withdraws_table.sql | 37 + .../20210307201830_add_deposits_table.sql | 32 + ...0531234123_add_kline_taker_buy_columns.sql | 35 + .../20211205162302_add_is_futures_column.sql | 18 + .../sqlite3/20211211020303_add_ftx_kline.sql | 31 + ...20211211034818_add_nav_history_details.sql | 27 + ...11211103657_update_fee_currency_length.sql | 10 + .../20211226022411_add_kucoin_klines.sql | 30 + .../20220304153309_add_profit_table.sql | 69 + .../sqlite3/20220307132917_add_positions.sql | 27 + .../20220317125555_fix_trade_indexes.sql | 19 + .../sqlite3/20220419121046_fix_fee_column.sql | 10 + .../20220503144849_add_margin_info_to_nav.sql | 12 + .../20220504184155_fix_net_asset_column.sql | 11 + ...0220512170330_fix_profit_symbol_length.sql | 12 + .../20220520140707_kline_unique_idx.sql | 47 + .../sqlite3/20220531012226_margin_loans.sql | 22 + .../sqlite3/20220531013327_margin_repays.sql | 22 + .../20220531013541_margin_interests.sql | 23 + .../20220531015005_margin_liquidations.sql | 31 + .../20230815173104_add_bybit_klines.sql | 30 + ...20231123125402_fix_order_status_length.sql | 12 + .../sqlite3/20240531163411_trades_created.sql | 23 + pkg/accounting/cost_distribution.go | 236 + pkg/accounting/cost_distribution_test.go | 184 + pkg/accounting/pnl/avg_cost.go | 129 + pkg/accounting/pnl/report.go | 100 + pkg/accounting/testdata/btcusdt-trades.json | 1 + pkg/backtest/assets_dummy.go | 65 + pkg/backtest/dumper.go | 97 + pkg/backtest/dumper_test.go | 54 + pkg/backtest/exchange.go | 451 + pkg/backtest/exchange_klinec.go | 13 + pkg/backtest/fee.go | 57 + pkg/backtest/fee_test.go | 124 + pkg/backtest/fixture_test.go | 93 + pkg/backtest/manifests.go | 47 + pkg/backtest/matching.go | 725 + pkg/backtest/matching_test.go | 529 + pkg/backtest/priceorder.go | 77 + pkg/backtest/recorder.go | 156 + pkg/backtest/recorder_test.go | 61 + pkg/backtest/report.go | 261 + pkg/backtest/simplepricematching_callbacks.go | 37 + pkg/backtest/utils.go | 57 + pkg/bbgo/activeorderbook.go | 491 + pkg/bbgo/activeorderbook_callbacks.go | 37 + pkg/bbgo/activeorderbook_test.go | 153 + pkg/bbgo/backtestfeemode_enumer.go | 117 + pkg/bbgo/bootstrap.go | 70 + pkg/bbgo/builder.go | 145 + pkg/bbgo/config.go | 708 + pkg/bbgo/config_test.go | 274 + pkg/bbgo/consts.go | 5 + pkg/bbgo/doc.go | 3 + pkg/bbgo/environment.go | 1050 + pkg/bbgo/envvar.go | 48 + pkg/bbgo/errors.go | 5 + pkg/bbgo/exchangeorderexecutor_callbacks.go | 27 + pkg/bbgo/exit.go | 157 + pkg/bbgo/exit_cumulated_volume_take_profit.go | 95 + pkg/bbgo/exit_hh_ll_stop.go | 253 + pkg/bbgo/exit_lower_shadow_take_profit.go | 65 + pkg/bbgo/exit_protective_stop_loss.go | 219 + pkg/bbgo/exit_roi_stop_loss.go | 69 + pkg/bbgo/exit_roi_take_profit.go | 54 + pkg/bbgo/exit_support_take_profit.go | 132 + pkg/bbgo/exit_test.go | 8 + pkg/bbgo/exit_trailing_stop.go | 192 + pkg/bbgo/exit_trailing_stop_test.go | 184 + pkg/bbgo/graceful_shutdown.go | 44 + pkg/bbgo/gracefulshutdown_callbacks.go | 18 + pkg/bbgo/indicator_set.go | 114 + pkg/bbgo/indicator_set_test.go | 58 + pkg/bbgo/interact.go | 635 + pkg/bbgo/interact_modify.go | 66 + pkg/bbgo/interact_test.go | 58 + pkg/bbgo/isolation.go | 56 + pkg/bbgo/isolation_test.go | 24 + pkg/bbgo/log.go | 1 + pkg/bbgo/marketdatastore.go | 67 + pkg/bbgo/marketdatastore_callbacks.go | 27 + pkg/bbgo/metrics.go | 179 + .../mocks/mock_order_executor_extended.go | 109 + pkg/bbgo/moving_average_settings.go | 46 + pkg/bbgo/notification.go | 113 + pkg/bbgo/order_execution.go | 421 + pkg/bbgo/order_executor_fast.go | 67 + pkg/bbgo/order_executor_general.go | 581 + pkg/bbgo/order_executor_simple.go | 71 + pkg/bbgo/order_processor.go | 62 + pkg/bbgo/order_processor_test.go | 56 + pkg/bbgo/persistence.go | 122 + pkg/bbgo/persistence_test.go | 152 + pkg/bbgo/profitstats.go | 1 + pkg/bbgo/quantity_amount.go | 40 + pkg/bbgo/quota.go | 67 + pkg/bbgo/reflect.go | 2 + pkg/bbgo/reflect_test.go | 2 + pkg/bbgo/reporter.go | 151 + pkg/bbgo/risk.go | 372 + pkg/bbgo/risk_controls.go | 74 + pkg/bbgo/risk_test.go | 323 + pkg/bbgo/scale.go | 441 + pkg/bbgo/scale_test.go | 236 + pkg/bbgo/serialmarketdatastore.go | 172 + pkg/bbgo/session.go | 1071 + pkg/bbgo/session_test.go | 44 + pkg/bbgo/source.go | 82 + pkg/bbgo/source_test.go | 34 + pkg/bbgo/standard_indicator_set.go | 187 + pkg/bbgo/stop_ema.go | 42 + pkg/bbgo/strategy_controller.go | 57 + pkg/bbgo/strategy_test.go | 64 + pkg/bbgo/strategycontroller_callbacks.go | 43 + pkg/bbgo/string.go | 1 + pkg/bbgo/testdata/backtest.yaml | 32 + pkg/bbgo/testdata/notification.yaml | 40 + pkg/bbgo/testdata/order_executor.yaml | 27 + pkg/bbgo/testdata/persistence.yaml | 28 + pkg/bbgo/testdata/strategy.yaml | 29 + pkg/bbgo/time.go | 15 + pkg/bbgo/trader.go | 465 + pkg/bbgo/trader_test.go | 1 + pkg/bbgo/trend_ema.go | 66 + pkg/bbgo/trend_ema_test.go | 21 + pkg/bbgo/wrapper.go | 7 + pkg/cache/cache.go | 178 + pkg/cache/cache_test.go | 103 + pkg/cache/home.go | 31 + pkg/cmd/account.go | 97 + pkg/cmd/backtest.go | 773 + pkg/cmd/balances.go | 67 + pkg/cmd/build.go | 59 + pkg/cmd/cancel.go | 166 + pkg/cmd/cmdutil/exchange.go | 1 + pkg/cmd/cmdutil/flags.go | 11 + pkg/cmd/cmdutil/signal.go | 27 + pkg/cmd/deposit.go | 70 + pkg/cmd/exchangetest.go | 63 + pkg/cmd/execute_order.go | 221 + pkg/cmd/hoptimize.go | 171 + pkg/cmd/import.go | 6 + pkg/cmd/kline.go | 107 + pkg/cmd/margin.go | 189 + pkg/cmd/market.go | 75 + pkg/cmd/optimize.go | 146 + pkg/cmd/orderbook.go | 172 + pkg/cmd/orders.go | 265 + pkg/cmd/pnl.go | 205 + pkg/cmd/root.go | 262 + pkg/cmd/run.go | 334 + pkg/cmd/strategy/builtin.go | 56 + pkg/cmd/sync.go | 86 + pkg/cmd/trades.go | 146 + pkg/cmd/transfer.go | 209 + pkg/cmd/userdatastream.go | 78 + pkg/cmd/utils.go | 33 + pkg/cmd/version.go | 23 + pkg/core/converter.go | 85 + pkg/core/converter_test.go | 31 + pkg/core/orderstore.go | 171 + pkg/core/tradecollector.go | 348 + pkg/core/tradecollector_callbacks.go | 48 + pkg/core/tradecollector_test.go | 87 + pkg/core/tradestore.go | 162 + pkg/core/tradestore_test.go | 39 + pkg/data/tsv/writer.go | 45 + pkg/datasource/coinmarketcap/datasource.go | 36 + pkg/datasource/coinmarketcap/v1/client.go | 55 + pkg/datasource/coinmarketcap/v1/listings.go | 56 + .../listings_historical_request_requestgen.go | 315 + .../v1/listings_latest_request_requestgen.go | 457 + .../v1/listings_new_request_requestgen.go | 226 + pkg/datasource/coinmarketcap/v1/types.go | 61 + pkg/datasource/glassnode/datasource.go | 78 + .../glassnode/glassnodeapi/client.go | 55 + .../glassnode/glassnodeapi/request.go | 23 + .../glassnodeapi/request_requestgen.go | 288 + .../glassnode/glassnodeapi/types.go | 121 + pkg/datasource/glassnode/types.go | 14 + pkg/datasource/wise/README.md | 25 + pkg/datasource/wise/client.go | 80 + pkg/datasource/wise/group.go | 9 + pkg/datasource/wise/rate.go | 10 + pkg/datasource/wise/rate_request.go | 27 + .../wise/rate_request_requestgen.go | 229 + pkg/datasource/wise/time.go | 34 + pkg/datatype/bools/slice.go | 54 + pkg/datatype/floats/funcs.go | 167 + pkg/datatype/floats/funcs_test.go | 23 + pkg/datatype/floats/map.go | 42 + pkg/datatype/floats/pivot.go | 30 + pkg/datatype/floats/pivot_test.go | 29 + pkg/datatype/floats/slice.go | 238 + pkg/datatype/floats/slice_test.go | 33 + pkg/datatype/string_slice.go | 57 + pkg/depth/buffer.go | 205 + pkg/depth/buffer_callbacks.go | 37 + pkg/depth/buffer_test.go | 157 + pkg/dynamic/call.go | 155 + pkg/dynamic/call_test.go | 115 + pkg/dynamic/can.go | 14 + pkg/dynamic/field.go | 113 + pkg/dynamic/field_test.go | 73 + pkg/dynamic/id.go | 30 + pkg/dynamic/inject.go | 130 + pkg/dynamic/inject_test.go | 105 + pkg/dynamic/iterate.go | 108 + pkg/dynamic/iterate_test.go | 131 + pkg/dynamic/merge.go | 41 + pkg/dynamic/merge_test.go | 82 + pkg/dynamic/print_config.go | 132 + pkg/dynamic/print_strategy.go | 97 + pkg/dynamic/typevalue.go | 24 + pkg/exchange/batch/batch_test.go | 1 + pkg/exchange/batch/closedorders.go | 42 + pkg/exchange/batch/deposit.go | 36 + pkg/exchange/batch/funding_fee.go | 41 + pkg/exchange/batch/kline.go | 37 + pkg/exchange/batch/margin_interest.go | 36 + pkg/exchange/batch/margin_liquidation.go | 37 + pkg/exchange/batch/margin_loan.go | 37 + pkg/exchange/batch/margin_repay.go | 37 + pkg/exchange/batch/option.go | 12 + pkg/exchange/batch/reward.go | 34 + pkg/exchange/batch/time_range_query.go | 125 + pkg/exchange/batch/time_range_query_test.go | 45 + pkg/exchange/batch/trade.go | 59 + pkg/exchange/batch/trade_test.go | 200 + pkg/exchange/batch/withdraw.go | 36 + pkg/exchange/batch/withdraw_test.go | 38 + pkg/exchange/binance/binanceapi/alias.go | 49 + .../binanceapi/cancel_replace_request.go | 48 + ...l_replace_spot_order_request_requestgen.go | 351 + pkg/exchange/binance/binanceapi/client.go | 257 + .../binance/binanceapi/client_test.go | 262 + ...futures_change_initial_leverage_request.go | 25 + ...nge_initial_leverage_request_requestgen.go | 157 + ...utures_change_multi_assets_mode_request.go | 29 + ...ge_multi_assets_mode_request_requestgen.go | 158 + .../binance/binanceapi/futures_client.go | 33 + .../futures_get_account_balance_request.go | 39 + ..._get_account_balance_request_requestgen.go | 135 + .../binanceapi/futures_get_account_request.go | 67 + .../futures_get_account_request_requestgen.go | 135 + ...res_get_global_long_short_account_ratio.go | 33 + .../futures_get_income_history_request.go | 58 + ...s_get_income_history_request_requestgen.go | 212 + .../futures_get_multi_assets_mode_request.go | 18 + ...et_multi_assets_mode_request_requestgen.go | 135 + .../binanceapi/futures_get_open_interest.go | 24 + ...es_get_open_interest_request_requestgen.go | 148 + .../futures_get_open_interest_statistics.go | 32 + ..._interest_statistics_request_requestgen.go | 214 + .../futures_get_position_risks_request.go | 37 + ...s_get_position_risks_request_requestgen.go | 148 + .../futures_get_taker_buy_sell_volume.go | 32 + ...get_top_trader_long_short_account_ratio.go | 33 + ...et_top_trader_long_short_position_ratio.go | 33 + ..._short_account_ratio_request_requestgen.go | 202 + ...aker_buy_sell_volume_request_requestgen.go | 202 + ..._short_account_ratio_request_requestgen.go | 202 + ...short_position_ratio_request_requestgen.go | 202 + .../binanceapi/futures_transfer_request.go | 33 + .../futures_transfer_request_requestgen.go | 178 + .../get_api_referral_if_new_user_request.go | 19 + ...referral_if_new_user_request_requestgen.go | 135 + .../binanceapi/get_deposit_address_request.go | 25 + .../get_deposit_address_request_requestgen.go | 161 + .../binanceapi/get_deposit_history_request.go | 51 + .../get_deposit_history_request_requestgen.go | 181 + .../binance/binanceapi/get_depth_request.go | 25 + .../get_depth_request_requestgen.go | 190 + .../get_historical_trades_request.go | 20 + ...et_historical_trades_request_requestgen.go | 175 + ...get_margin_borrow_repay_history_request.go | 64 + ...borrow_repay_history_request_requestgen.go | 273 + ...argin_borrow_repay_history_request_test.go | 29 + .../get_margin_interest_history_request.go | 52 + ...gin_interest_history_request_requestgen.go | 234 + ...et_margin_interest_history_request_test.go | 29 + ...et_margin_interest_rate_history_request.go | 30 + ...nterest_rate_history_request_requestgen.go | 178 + .../get_margin_liquidation_history_request.go | 38 + ..._liquidation_history_request_requestgen.go | 211 + .../get_margin_max_borrowable_request.go | 25 + ...argin_max_borrowable_request_requestgen.go | 161 + .../binanceapi/get_margin_trades_request.go | 24 + .../get_margin_trades_request_requestgen.go | 260 + .../binanceapi/get_my_trades_request.go | 27 + .../get_my_trades_request_requestgen.go | 218 + .../get_spot_rebate_history_request.go | 42 + ..._spot_rebate_history_request_requestgen.go | 172 + .../binanceapi/get_trade_fee_request.go | 22 + .../get_trade_fee_request_requestgen.go | 135 + .../get_withdraw_history_request.go | 68 + ...get_withdraw_history_request_requestgen.go | 273 + pkg/exchange/binance/binanceapi/page.go | 15 + .../binanceapi/place_margin_order_request.go | 28 + .../place_margin_order_request_requestgen.go | 220 + pkg/exchange/binance/binanceapi/rows.go | 8 + .../binanceapi/transfer_asset_request.go | 36 + .../transfer_asset_request_requestgen.go | 222 + .../binance/binanceapi/transfertype_string.go | 24 + .../binance/binanceapi/withdraw_request.go | 41 + .../binanceapi/withdraw_request_requestgen.go | 256 + .../binanceapi/withdrawstatus_string.go | 29 + pkg/exchange/binance/cancel_replace.go | 71 + pkg/exchange/binance/convert.go | 377 + pkg/exchange/binance/convert_futures.go | 290 + pkg/exchange/binance/convert_margin.go | 115 + pkg/exchange/binance/exchange.go | 1550 ++ pkg/exchange/binance/exchange_test.go | 34 + pkg/exchange/binance/futures.go | 413 + pkg/exchange/binance/historical_trades.go | 29 + pkg/exchange/binance/margin_history.go | 157 + pkg/exchange/binance/parse.go | 1181 ++ pkg/exchange/binance/parse_test.go | 414 + pkg/exchange/binance/reward.go | 45 + pkg/exchange/binance/stream.go | 504 + pkg/exchange/binance/stream_callbacks.go | 235 + pkg/exchange/binance/ticker_test.go | 54 + pkg/exchange/bitget/bitgetapi/client.go | 181 + .../bitgetapi/v2/cancel_order_request.go | 29 + .../v2/cancel_order_request_requestgen.go | 196 + pkg/exchange/bitget/bitgetapi/v2/client.go | 22 + .../bitget/bitgetapi/v2/client_test.go | 110 + .../v2/get_account_assets_request.go | 39 + .../get_account_assets_request_requestgen.go | 195 + .../v2/get_history_orders_request.go | 103 + .../get_history_orders_request_requestgen.go | 243 + .../v2/get_history_orders_request_test.go | 121 + .../bitget/bitgetapi/v2/get_k_line.go | 83 + .../v2/get_k_line_request_requestgen.go | 224 + .../bitgetapi/v2/get_symbols_request.go | 49 + .../v2/get_symbols_request_requestgen.go | 172 + .../bitgetapi/v2/get_tickers_request.go | 40 + .../v2/get_tickers_request_requestgen.go | 174 + .../bitget/bitgetapi/v2/get_trade_fills.go | 72 + .../v2/get_trade_fills_request_requestgen.go | 240 + .../v2/get_unfilled_orders_request.go | 56 + .../get_unfilled_orders_request_requestgen.go | 243 + .../bitgetapi/v2/place_order_request.go | 29 + .../v2/place_order_request_requestgen.go | 251 + .../v2/testdata/cancel_order_request.json | 9 + .../testdata/get_account_assets_request.json | 23 + .../testdata/get_history_orders_request.json | 45 + ...get_history_orders_request_market_buy.json | 26 + .../v2/testdata/get_k_line_request.json | 27 + .../v2/testdata/get_symbols_request.json | 58 + .../v2/testdata/get_ticker_request.json | 25 + .../v2/testdata/get_tickers_request.json | 43 + .../v2/testdata/get_trade_fills_request.json | 87 + ...t_unfilled_orders_request_limit_order.json | 25 + ...illed_orders_request_market_buy_order.json | 25 + ...lled_orders_request_market_sell_order.json | 25 + .../v2/testdata/place_order_request.json | 9 + .../bitgetapi/v2/testdata/request_error.json | 6 + pkg/exchange/bitget/bitgetapi/v2/types.go | 42 + pkg/exchange/bitget/convert.go | 497 + pkg/exchange/bitget/convert_test.go | 1200 ++ pkg/exchange/bitget/debug.go | 19 + pkg/exchange/bitget/exchange.go | 599 + pkg/exchange/bitget/exchange_test.go | 1637 ++ pkg/exchange/bitget/stream.go | 477 + pkg/exchange/bitget/stream_callbacks.go | 55 + pkg/exchange/bitget/stream_test.go | 722 + pkg/exchange/bitget/types.go | 493 + pkg/exchange/bitget/types_test.go | 40 + .../bybit/bybitapi/cancel_order_request.go | 35 + .../cancel_order_request_requestgen.go | 237 + pkg/exchange/bybit/bybitapi/client.go | 186 + pkg/exchange/bybit/bybitapi/client_test.go | 183 + .../bybitapi/get_account_info_request.go | 24 + .../get_account_info_request_requestgen.go | 157 + .../bybit/bybitapi/get_fee_rates_request.go | 38 + .../get_fee_rates_request_requestgen.go | 207 + .../bybitapi/get_instruments_info_request.go | 56 + ...get_instruments_info_request_requestgen.go | 220 + .../bybit/bybitapi/get_k_lines_request.go | 107 + .../get_k_lines_request_requestgen.go | 255 + .../bybitapi/get_k_lines_request_test.go | 175 + .../bybit/bybitapi/get_open_orders_request.go | 104 + .../get_open_orders_request_requestgen.go | 309 + .../bybitapi/get_order_histories_request.go | 52 + .../get_order_histories_request_requestgen.go | 313 + .../bybit/bybitapi/get_tickers_request.go | 72 + .../get_tickers_request_requestgen.go | 190 + .../bybitapi/get_wallet_balances_request.go | 92 + .../get_wallet_balances_request_requestgen.go | 194 + .../bybit/bybitapi/place_order_request.go | 57 + .../place_order_request_requestgen.go | 546 + pkg/exchange/bybit/bybitapi/types.go | 130 + pkg/exchange/bybit/bybitapi/types_test.go | 41 + pkg/exchange/bybit/bybitapi/v3/client.go | 17 + pkg/exchange/bybit/bybitapi/v3/client_test.go | 44 + .../bybit/bybitapi/v3/get_trades_request.go | 55 + .../v3/get_trades_request_requestgen.go | 256 + pkg/exchange/bybit/bybitapi/v3/types.go | 15 + pkg/exchange/bybit/convert.go | 389 + pkg/exchange/bybit/convert_test.go | 866 + pkg/exchange/bybit/exchange.go | 604 + pkg/exchange/bybit/market_info_poller.go | 142 + pkg/exchange/bybit/market_info_poller_test.go | 173 + pkg/exchange/bybit/mocks/stream.go | 82 + pkg/exchange/bybit/stream.go | 482 + pkg/exchange/bybit/stream_callbacks.go | 67 + pkg/exchange/bybit/stream_test.go | 467 + pkg/exchange/bybit/types.go | 430 + pkg/exchange/bybit/types_test.go | 889 + pkg/exchange/factory.go | 74 + pkg/exchange/kucoin/convert.go | 246 + pkg/exchange/kucoin/exchange.go | 445 + pkg/exchange/kucoin/generate_symbol_map.go | 77 + pkg/exchange/kucoin/kucoinapi/account.go | 39 + pkg/exchange/kucoin/kucoinapi/bullet.go | 67 + .../cancel_all_order_request_requestgen.go | 143 + .../cancel_order_request_requestgen.go | 111 + pkg/exchange/kucoin/kucoinapi/client.go | 155 + .../kucoin/kucoinapi/get_account_request.go | 16 + .../get_account_request_requestgen.go | 131 + .../get_all_tickers_request_requestgen.go | 115 + .../kucoinapi/get_fills_request_requestgen.go | 239 + .../get_k_lines_request_requestgen.go | 142 + ...ok_level_2_depth_100_request_requestgen.go | 128 + ...ook_level_2_depth_20_request_requestgen.go | 128 + ...ok_level_2_depth_all_request_requestgen.go | 128 + .../get_private_bullet_request_requestgen.go | 115 + .../get_public_bullet_request_requestgen.go | 115 + .../get_ticker_request_requestgen.go | 128 + .../kucoin/kucoinapi/list_accounts_request.go | 15 + .../list_accounts_request_requestgen.go | 115 + .../list_history_orders_request_requestgen.go | 161 + .../list_orders_request_requestgen.go | 239 + .../list_sub_accounts_request_requestgen.go | 115 + .../list_symbols_request_requestgen.go | 127 + pkg/exchange/kucoin/kucoinapi/marketdata.go | 362 + .../place_order_request_requestgen.go | 251 + pkg/exchange/kucoin/kucoinapi/trade.go | 337 + pkg/exchange/kucoin/kucoinapi/types.go | 64 + pkg/exchange/kucoin/parse.go | 104 + pkg/exchange/kucoin/stream.go | 317 + pkg/exchange/kucoin/stream_callbacks.go | 65 + pkg/exchange/kucoin/symbols.go | 1117 + pkg/exchange/kucoin/testdata/ack.json | 4 + .../testdata/btc-01-account-balance.json | 24 + .../kucoin/testdata/btc-02-trade-orders.json | 25 + .../kucoin/testdata/btc-03-trade-orders.json | 21 + .../testdata/btc-04-account-balance.json | 25 + .../testdata/cro-01-account-balance.json | 24 + .../kucoin/testdata/cro-02-trade-orders.json | 21 + .../kucoin/testdata/cro-03-trade-orders.json | 25 + .../kucoin/testdata/cro-04-trade-orders.json | 21 + .../testdata/cro-05-account-balance.json | 25 + .../testdata/cro-06-account-balance.json | 25 + .../testdata/cro-07-account-balance.json | 24 + .../kucoin/testdata/cro-08-trade-orders.json | 21 + .../kucoin/testdata/cro-09-trade-orders.json | 25 + .../kucoin/testdata/cro-10-trade-orders.json | 21 + .../testdata/cro-11-account-balance.json | 25 + .../testdata/cro-12-account-balance.json | 25 + pkg/exchange/kucoin/testdata/welcome.json | 4 + pkg/exchange/kucoin/websocket.go | 159 + pkg/exchange/max/client_order_id.go | 42 + pkg/exchange/max/convert.go | 386 + pkg/exchange/max/convert_test.go | 116 + pkg/exchange/max/exchange.go | 1232 ++ pkg/exchange/max/margin.go | 43 + pkg/exchange/max/maxapi/account.go | 225 + pkg/exchange/max/maxapi/account_test.go | 112 + pkg/exchange/max/maxapi/auth.go | 16 + .../max/maxapi/cancel_order_request.go | 19 + .../maxapi/cancel_order_request_requestgen.go | 163 + .../max/maxapi/create_order_request.go | 26 + .../maxapi/create_order_request_requestgen.go | 247 + .../maxapi/get_account_request_requestgen.go | 183 + .../maxapi/get_accounts_request_requestgen.go | 167 + .../get_deposit_history_request_requestgen.go | 238 + .../max/maxapi/get_k_lines_request.go | 27 + .../maxapi/get_k_lines_request_requestgen.go | 193 + .../max/maxapi/get_markets_request.go | 18 + .../maxapi/get_markets_request_requestgen.go | 135 + .../get_rewards_of_type_request_requestgen.go | 222 + .../maxapi/get_rewards_request_requestgen.go | 216 + pkg/exchange/max/maxapi/get_ticker_request.go | 20 + .../maxapi/get_ticker_request_requestgen.go | 154 + .../max/maxapi/get_tickers_request.go | 20 + .../maxapi/get_tickers_request_requestgen.go | 135 + .../max/maxapi/get_timestamp_request.go | 20 + .../get_timestamp_request_requestgen.go | 135 + .../get_vip_level_request_requestgen.go | 167 + ...get_withdraw_history_request_requestgen.go | 238 + ...withdrawal_addresses_request_requestgen.go | 154 + pkg/exchange/max/maxapi/order.go | 108 + pkg/exchange/max/maxapi/order_test.go | 24 + pkg/exchange/max/maxapi/public.go | 184 + pkg/exchange/max/maxapi/public_parser.go | 314 + pkg/exchange/max/maxapi/public_test.go | 70 + pkg/exchange/max/maxapi/restapi.go | 356 + pkg/exchange/max/maxapi/reward.go | 169 + pkg/exchange/max/maxapi/reward_test.go | 43 + pkg/exchange/max/maxapi/trade.go | 154 + pkg/exchange/max/maxapi/userdata.go | 250 + pkg/exchange/max/maxapi/userdata_test.go | 45 + .../max/maxapi/v3/cancel_order_request.go | 19 + .../v3/cancel_order_request_requestgen.go | 164 + .../v3/cancel_wallet_order_all_request.go | 26 + ...cel_wallet_order_all_request_requestgen.go | 200 + .../maxapi/v3/create_wallet_order_request.go | 27 + .../create_wallet_order_request_requestgen.go | 270 + .../maxapi/v3/get_margin_ad_ratio_request.go | 26 + .../get_margin_ad_ratio_request_requestgen.go | 135 + ...gin_borrowing_limits_request_requestgen.go | 135 + .../v3/get_margin_interest_history_request.go | 35 + ...gin_interest_history_request_requestgen.go | 197 + .../v3/get_margin_interest_rates_request.go | 27 + ...argin_interest_rates_request_requestgen.go | 135 + .../get_margin_liquidation_history_request.go | 38 + ..._liquidation_history_request_requestgen.go | 181 + .../v3/get_margin_loan_history_request.go | 38 + ..._margin_loan_history_request_requestgen.go | 197 + .../get_margin_repayment_history_request.go | 34 + ...in_repayment_history_request_requestgen.go | 197 + .../max/maxapi/v3/get_order_request.go | 19 + .../maxapi/v3/get_order_request_requestgen.go | 165 + .../max/maxapi/v3/get_order_trades_request.go | 19 + .../v3/get_order_trades_request_requestgen.go | 164 + .../maxapi/v3/get_wallet_accounts_request.go | 19 + .../get_wallet_accounts_request_requestgen.go | 174 + .../v3/get_wallet_closed_orders_request.go | 27 + ...wallet_closed_orders_request_requestgen.go | 219 + .../v3/get_wallet_open_orders_request.go | 26 + ...t_wallet_open_orders_request_requestgen.go | 219 + .../v3/get_wallet_order_history_request.go | 22 + ...wallet_order_history_request_requestgen.go | 203 + .../maxapi/v3/get_wallet_trades_request.go | 28 + .../get_wallet_trades_request_requestgen.go | 242 + pkg/exchange/max/maxapi/v3/margin.go | 27 + .../max/maxapi/v3/margin_loan_request.go | 19 + .../v3/margin_loan_request_requestgen.go | 163 + .../max/maxapi/v3/margin_repay_request.go | 19 + .../v3/margin_repay_request_requestgen.go | 163 + .../max/maxapi/v3/margin_transfer_request.go | 41 + .../v3/margin_transfer_request_requestgen.go | 184 + pkg/exchange/max/maxapi/v3/order.go | 19 + pkg/exchange/max/maxapi/v3/trade.go | 42 + pkg/exchange/max/maxapi/websocket.go | 30 + pkg/exchange/max/maxapi/withdrawal.go | 81 + .../maxapi/withdrawal_request_requestgen.go | 179 + pkg/exchange/max/maxapi/withdrawal_test.go | 27 + pkg/exchange/max/stream.go | 306 + pkg/exchange/max/stream_callbacks.go | 147 + pkg/exchange/max/ticker_test.go | 54 + pkg/exchange/okex/convert.go | 364 + pkg/exchange/okex/convert_test.go | 245 + pkg/exchange/okex/exchange.go | 660 + pkg/exchange/okex/exchange_test.go | 386 + pkg/exchange/okex/gensymbols.go | 52 + pkg/exchange/okex/kline_stream.go | 94 + pkg/exchange/okex/klinestream_callbacks.go | 19 + .../okex/okexapi/cancel_order_request.go | 21 + .../cancel_order_request_requestgen.go | 195 + pkg/exchange/okex/okexapi/client.go | 260 + pkg/exchange/okex/okexapi/client_test.go | 348 + .../okex/okexapi/get_account_info_request.go | 40 + .../get_account_info_request_requestgen.go | 157 + .../okex/okexapi/get_candles_request.go | 137 + .../okexapi/get_candles_request_requestgen.go | 226 + .../okexapi/get_instruments_info_request.go | 47 + ...get_instruments_info_request_requestgen.go | 194 + .../okex/okexapi/get_open_orders_request.go | 43 + .../get_open_orders_request_requestgen.go | 321 + .../okex/okexapi/get_order_history_request.go | 110 + .../get_order_history_request_requestgen.go | 339 + ..._three_days_transaction_history_request.go | 39 + ..._transaction_history_request_requestgen.go | 322 + .../okex/okexapi/get_ticker_request.go | 21 + .../okexapi/get_ticker_request_requestgen.go | 170 + .../okex/okexapi/get_tickers_request.go | 51 + .../okexapi/get_tickers_request_requestgen.go | 181 + .../get_transaction_history_request.go | 86 + ..._transaction_history_request_requestgen.go | 322 + pkg/exchange/okex/okexapi/market.go | 102 + .../okex/okexapi/place_order_request.go | 70 + .../okexapi/place_order_request_requestgen.go | 305 + pkg/exchange/okex/okexapi/public.go | 67 + ...hree_days_transaction_history_request.json | 32 + .../get_transaction_history_request.json | 32 + pkg/exchange/okex/okexapi/trade.go | 311 + pkg/exchange/okex/parse.go | 437 + pkg/exchange/okex/parse_test.go | 1181 ++ pkg/exchange/okex/query_closed_orders_test.go | 66 + pkg/exchange/okex/query_kline_test.go | 85 + pkg/exchange/okex/query_order_test.go | 36 + pkg/exchange/okex/query_order_trades_test.go | 40 + pkg/exchange/okex/query_trades_test.go | 82 + pkg/exchange/okex/stream.go | 324 + pkg/exchange/okex/stream_callbacks.go | 69 + pkg/exchange/okex/stream_test.go | 188 + pkg/exchange/okex/symbols.go | 560 + pkg/exchange/okex/types.go | 40 + pkg/exchange/retry/account.go | 43 + pkg/exchange/retry/order.go | 228 + pkg/exchange/retry/ticker.go | 17 + pkg/exchange/retry/trade.go | 42 + pkg/exchange/util.go | 37 + pkg/fixedpoint/const.go | 7 + pkg/fixedpoint/convert.go | 612 + pkg/fixedpoint/convert_test.go | 124 + pkg/fixedpoint/count.go | 13 + pkg/fixedpoint/dec.go | 1367 ++ pkg/fixedpoint/dec_dnum_test.go | 44 + pkg/fixedpoint/dec_legacy_test.go | 33 + pkg/fixedpoint/dec_test.go | 304 + pkg/fixedpoint/div128.go | 134 + pkg/fixedpoint/filter.go | 20 + pkg/fixedpoint/helpers.go | 15 + pkg/fixedpoint/reduce.go | 25 + pkg/fixedpoint/reduce_test.go | 37 + pkg/fixedpoint/slice.go | 24 + pkg/fixedpoint/slice_test.go | 35 + pkg/grpc/convert.go | 237 + pkg/grpc/server.go | 355 + pkg/indicator/ad.go | 66 + pkg/indicator/ad_callbacks.go | 15 + pkg/indicator/alma.go | 92 + pkg/indicator/alma_callbacks.go | 15 + pkg/indicator/alma_test.go | 61 + pkg/indicator/atr.go | 111 + pkg/indicator/atr_callbacks.go | 15 + pkg/indicator/atr_test.go | 76 + pkg/indicator/atrp.go | 123 + pkg/indicator/atrp_callbacks.go | 15 + pkg/indicator/boll.go | 143 + pkg/indicator/boll_callbacks.go | 15 + pkg/indicator/boll_test.go | 69 + pkg/indicator/ca_callbacks.go | 15 + pkg/indicator/cci.go | 108 + pkg/indicator/cci_callbacks.go | 15 + pkg/indicator/cci_test.go | 38 + pkg/indicator/cma.go | 57 + pkg/indicator/const.go | 11 + pkg/indicator/dema.go | 103 + pkg/indicator/dema_callbacks.go | 15 + pkg/indicator/dema_test.go | 55 + pkg/indicator/dmi.go | 117 + pkg/indicator/dmi_callbacks.go | 15 + pkg/indicator/dmi_test.go | 87 + pkg/indicator/drift.go | 142 + pkg/indicator/drift_callbacks.go | 15 + pkg/indicator/drift_test.go | 40 + pkg/indicator/emv.go | 74 + pkg/indicator/emv_callbacks.go | 15 + pkg/indicator/emv_test.go | 34 + pkg/indicator/ewma.go | 92 + pkg/indicator/ewma_callbacks.go | 15 + pkg/indicator/ewma_test.go | 1079 + pkg/indicator/fisher.go | 80 + pkg/indicator/fishertransform_callbacks.go | 15 + pkg/indicator/ghfilter.go | 66 + pkg/indicator/ghfilter_callbacks.go | 15 + pkg/indicator/ghfilter_test.go | 6151 ++++++ pkg/indicator/gma.go | 76 + pkg/indicator/gma_callbacks.go | 15 + pkg/indicator/gma_test.go | 61 + pkg/indicator/hull.go | 68 + pkg/indicator/hull_callbacks.go | 15 + pkg/indicator/hull_test.go | 60 + pkg/indicator/interface.go | 34 + pkg/indicator/kalmanfilter.go | 78 + pkg/indicator/kalmanfilter_callbacks.go | 15 + pkg/indicator/kalmanfilter_test.go | 6191 ++++++ pkg/indicator/klingeroscillator.go | 99 + pkg/indicator/klingeroscillator_callbacks.go | 15 + pkg/indicator/klingeroscillator_test.go | 53 + pkg/indicator/line.go | 80 + pkg/indicator/linreg.go | 120 + pkg/indicator/linreg_callbacks.go | 15 + pkg/indicator/macd.go | 115 + pkg/indicator/macd_test.go | 55 + pkg/indicator/macdlegacy_callbacks.go | 15 + pkg/indicator/obv.go | 86 + pkg/indicator/obv_callbacks.go | 15 + pkg/indicator/obv_test.go | 62 + pkg/indicator/pivot.go | 117 + pkg/indicator/pivot_callbacks.go | 15 + pkg/indicator/pivothigh.go | 64 + pkg/indicator/pivothigh_callbacks.go | 15 + pkg/indicator/pivotlow.go | 76 + pkg/indicator/pivotlow_callbacks.go | 15 + pkg/indicator/pivotlow_test.go | 51 + pkg/indicator/psar.go | 121 + pkg/indicator/psar_callbacks.go | 15 + pkg/indicator/psar_test.go | 40 + pkg/indicator/rma.go | 123 + pkg/indicator/rma_callbacks.go | 15 + pkg/indicator/rma_test.go | 72 + pkg/indicator/rsi.go | 109 + pkg/indicator/rsi_callbacks.go | 15 + pkg/indicator/rsi_test.go | 70 + pkg/indicator/sma.go | 83 + pkg/indicator/sma_callbacks.go | 15 + pkg/indicator/sma_test.go | 68 + pkg/indicator/ssf.go | 103 + pkg/indicator/ssf_callbacks.go | 15 + pkg/indicator/ssf_test.go | 71 + pkg/indicator/stddev.go | 56 + pkg/indicator/stddev_callbacks.go | 15 + pkg/indicator/stoch.go | 83 + pkg/indicator/stoch_callbacks.go | 15 + pkg/indicator/stoch_test.go | 78 + pkg/indicator/supertrend.go | 205 + pkg/indicator/supertrendPivot.go | 213 + pkg/indicator/supertrendPivot_callbacks.go | 15 + pkg/indicator/supertrend_callbacks.go | 15 + pkg/indicator/tema.go | 88 + pkg/indicator/tema_callbacks.go | 15 + pkg/indicator/tema_test.go | 56 + pkg/indicator/till.go | 134 + pkg/indicator/till_callbacks.go | 15 + pkg/indicator/till_test.go | 66 + pkg/indicator/tma.go | 50 + pkg/indicator/tma_callbacks.go | 15 + pkg/indicator/tsi.go | 100 + pkg/indicator/tsi_callbacks.go | 15 + pkg/indicator/tsi_test.go | 36 + pkg/indicator/utBotAlert.go | 154 + pkg/indicator/utBotAlert_callbacks.go | 17 + pkg/indicator/util.go | 15 + pkg/indicator/v2/adx.go | 72 + pkg/indicator/v2/adx_test.go | 77 + pkg/indicator/v2/atr.go | 12 + pkg/indicator/v2/atr_test.go | 81 + pkg/indicator/v2/atrp.go | 23 + pkg/indicator/v2/boll.go | 57 + pkg/indicator/v2/cci.go | 65 + pkg/indicator/v2/cci_test.go | 39 + pkg/indicator/v2/cma.go | 28 + pkg/indicator/v2/const.go | 5 + pkg/indicator/v2/cross.go | 60 + pkg/indicator/v2/ewma.go | 30 + pkg/indicator/v2/keltner.go | 61 + pkg/indicator/v2/klines.go | 68 + pkg/indicator/v2/klinestream_callbacks.go | 17 + pkg/indicator/v2/macd.go | 33 + pkg/indicator/v2/macd_test.go | 65 + pkg/indicator/v2/multiply.go | 45 + pkg/indicator/v2/pivothigh.go | 39 + pkg/indicator/v2/pivotlow.go | 39 + pkg/indicator/v2/price.go | 71 + pkg/indicator/v2/rma.go | 63 + pkg/indicator/v2/rma_test.go | 65 + pkg/indicator/v2/rsi.go | 62 + pkg/indicator/v2/rsi_test.go | 87 + pkg/indicator/v2/sma.go | 33 + pkg/indicator/v2/sma_test.go | 22 + pkg/indicator/v2/smma.go | 47 + pkg/indicator/v2/smma_test.go | 27 + pkg/indicator/v2/stddev.go | 28 + pkg/indicator/v2/stoch.go | 64 + pkg/indicator/v2/stoch_test.go | 80 + pkg/indicator/v2/stochstream_callbacks.go | 15 + pkg/indicator/v2/subtract.go | 49 + pkg/indicator/v2/subtract_test.go | 30 + pkg/indicator/v2/tr.go | 49 + pkg/indicator/v2/tr_test.go | 82 + pkg/indicator/vidya.go | 108 + pkg/indicator/vidya_callbacks.go | 15 + pkg/indicator/vidya_test.go | 19 + pkg/indicator/volatility.go | 110 + pkg/indicator/volatility_callbacks.go | 15 + pkg/indicator/volumeprofile.go | 117 + pkg/indicator/volumeprofile_test.go | 29 + pkg/indicator/vwap.go | 108 + pkg/indicator/vwap_callbacks.go | 15 + pkg/indicator/vwap_test.go | 74 + pkg/indicator/vwma.go | 113 + pkg/indicator/vwma_callbacks.go | 15 + pkg/indicator/wdrift.go | 147 + pkg/indicator/wdrift_test.go | 47 + pkg/indicator/weighteddrift_callbacks.go | 15 + pkg/indicator/wwma.go | 88 + pkg/indicator/wwma_callbacks.go | 15 + pkg/indicator/zlema.go | 93 + pkg/indicator/zlema_callbacks.go | 15 + pkg/indicator/zlema_test.go | 55 + pkg/interact/auth.go | 129 + pkg/interact/command.go | 89 + pkg/interact/default.go | 21 + pkg/interact/interact.go | 281 + pkg/interact/interact_test.go | 143 + pkg/interact/parse.go | 134 + pkg/interact/reply.go | 65 + pkg/interact/responder.go | 16 + pkg/interact/session.go | 47 + pkg/interact/slack.go | 551 + pkg/interact/slack_callbacks.go | 27 + pkg/interact/state.go | 8 + pkg/interact/telegram.go | 286 + pkg/interact/telegram_callbacks.go | 15 + .../mysql/main_20200721225616_trades.go | 53 + .../mysql/main_20200819054742_trade_index.go | 29 + .../mysql/main_20201102222546_orders.go | 45 + ...main_20201103173342_trades_add_order_id.go | 29 + .../main_20201105092857_trades_index_fix.go | 29 + .../main_20201105093056_orders_add_index.go | 29 + .../mysql/main_20201106114742_klines.go | 61 + .../main_20201211175751_fix_symbol_length.go | 29 + .../main_20210118163847_fix_unique_index.go | 29 + .../main_20210119232826_add_margin_columns.go | 29 + ...210129182704_trade_price_quantity_index.go | 29 + .../main_20210215203116_add_pnl_column.go | 29 + .../main_20210223080622_add_rewards_table.go | 29 + ...main_20210301140656_add_withdraws_table.go | 29 + .../main_20210307201830_add_deposits_table.go | 29 + ...ain_20210416230730_klines_symbol_length.go | 53 + ...n_20210421091430_increase_symbol_length.go | 53 + ..._20210421095030_increase_decimal_length.go | 53 + ...10531234123_add_kline_taker_buy_columns.go | 49 + ...in_20211205162043_add_is_futures_column.go | 37 + .../main_20211211020303_add_ftx_kline.go | 33 + ..._20211211034819_add_nav_history_details.go | 33 + ...211211103657_update_fee_currency_length.go | 29 + .../main_20211226022411_add_kucoin_klines.go | 29 + .../main_20220304153317_add_profit_table.go | 29 + .../main_20220307132917_add_positions.go | 29 + .../main_20220317125555_fix_trade_indexes.go | 69 + .../main_20220419121046_fix_fee_column.go | 37 + ...n_20220503144849_add_margin_info_to_nav.go | 29 + ...ain_20220504184155_fix_net_asset_column.go | 33 + ...20220512170322_fix_profit_symbol_length.go | 29 + .../main_20220520140707_kline_unique_idx.go | 61 + .../mysql/main_20220531012226_margin_loans.go | 29 + .../main_20220531013327_margin_repays.go | 29 + .../main_20220531013542_margin_interests.go | 29 + ...main_20220531015005_margin_liquidations.go | 29 + .../main_20230815173104_add_bybit_klines.go | 29 + ..._20231123125402_fix_order_status_length.go | 29 + .../main_20240531163411_trades_created.go | 33 + pkg/migrations/mysql/migration_api.go | 91 + pkg/migrations/mysql/migration_api_test.go | 21 + .../sqlite3/main_20200721225616_trades.go | 29 + .../main_20200819054742_trade_index.go | 45 + .../sqlite3/main_20201102222546_orders.go | 29 + ...main_20201103173342_trades_add_order_id.go | 29 + .../main_20201105092857_trades_index_fix.go | 69 + .../main_20201105093056_orders_add_index.go | 37 + .../sqlite3/main_20201106114742_klines.go | 61 + .../main_20210118163847_fix_unique_index.go | 29 + .../main_20210119232826_add_margin_columns.go | 53 + ...210129182704_trade_price_quantity_index.go | 29 + .../main_20210215203111_add_pnl_column.go | 37 + .../main_20210223080622_add_rewards_table.go | 29 + ...main_20210301140656_add_withdraws_table.go | 37 + .../main_20210307201830_add_deposits_table.go | 37 + ...10531234123_add_kline_taker_buy_columns.go | 37 + ...in_20211205162302_add_is_futures_column.go | 37 + .../main_20211211020303_add_ftx_kline.go | 29 + ..._20211211034818_add_nav_history_details.go | 33 + ...211211103657_update_fee_currency_length.go | 29 + .../main_20211226022411_add_kucoin_klines.go | 29 + .../main_20220304153309_add_profit_table.go | 29 + .../main_20220307132917_add_positions.go | 29 + .../main_20220317125555_fix_trade_indexes.go | 69 + .../main_20220419121046_fix_fee_column.go | 29 + ...n_20220503144849_add_margin_info_to_nav.go | 53 + ...ain_20220504184155_fix_net_asset_column.go | 29 + ...20220512170330_fix_profit_symbol_length.go | 29 + .../main_20220520140707_kline_unique_idx.go | 61 + .../main_20220531012226_margin_loans.go | 29 + .../main_20220531013327_margin_repays.go | 29 + .../main_20220531013541_margin_interests.go | 29 + ...main_20220531015005_margin_liquidations.go | 29 + .../main_20230815173104_add_bybit_klines.go | 29 + ..._20231123125402_fix_order_status_length.go | 29 + .../main_20240531163411_trades_created.go | 29 + pkg/migrations/sqlite3/migration_api.go | 91 + pkg/migrations/sqlite3/migration_api_test.go | 21 + pkg/net/websocketbase/client.go | 100 + .../websocketclientbase_callbacks.go | 47 + pkg/notifier/slacknotifier/slack.go | 164 + pkg/notifier/telegramnotifier/logrus_look.go | 45 + pkg/notifier/telegramnotifier/telegram.go | 256 + pkg/optimizer/config.go | 105 + pkg/optimizer/format.go | 142 + pkg/optimizer/grid.go | 324 + pkg/optimizer/hpoptimizer.go | 303 + pkg/optimizer/hpoptimizer_test.go | 201 + pkg/optimizer/hyperparam.go | 105 + pkg/optimizer/local.go | 204 + pkg/optimizer/local_test.go | 21 + pkg/optimizer/operator.go | 3 + pkg/pb/README.md | 9 + pkg/pb/bbgo.pb.go | 3208 +++ pkg/pb/bbgo.proto | 280 + pkg/pb/bbgo_grpc.pb.go | 510 + pkg/pricesolver/simple.go | 119 + pkg/pricesolver/simple_test.go | 145 + pkg/report/profit_report.go | 177 + pkg/report/profit_stats_tracker.go | 96 + pkg/risk/circuitbreaker/basic.go | 268 + pkg/risk/dynamicrisk/dynamic_exposure.go | 86 + pkg/risk/dynamicrisk/dynamic_quantity.go | 100 + pkg/risk/dynamicrisk/dynamic_spread.go | 247 + pkg/risk/leverage.go | 51 + pkg/risk/leverage_test.go | 145 + pkg/risk/riskcontrol/circuit_break.go | 67 + pkg/risk/riskcontrol/circuit_break_test.go | 81 + pkg/risk/riskcontrol/order_price_risk.go | 35 + pkg/risk/riskcontrol/order_price_risk_test.go | 63 + pkg/risk/riskcontrol/position.go | 103 + pkg/risk/riskcontrol/position_test.go | 118 + .../positionriskcontrol_callbacks.go | 18 + pkg/server/asset_fs.go | 22 + pkg/server/assets_dummy.go | 9 + pkg/server/envvars.go | 41 + pkg/server/ping.go | 45 + pkg/server/routes.go | 650 + pkg/server/setup.go | 159 + pkg/server/utils.go | 67 + pkg/service/account.go | 65 + pkg/service/account_test.go | 41 + pkg/service/backtest.go | 584 + pkg/service/backtest_test.go | 187 + pkg/service/database.go | 103 + pkg/service/db_test.go | 48 + pkg/service/deposit.go | 102 + pkg/service/deposit_test.go | 1 + pkg/service/errors.go | 5 + pkg/service/google/sheets.go | 178 + pkg/service/margin.go | 147 + pkg/service/margin_test.go | 52 + pkg/service/memory.go | 62 + pkg/service/memory_test.go | 33 + pkg/service/order.go | 214 + pkg/service/order_test.go | 24 + pkg/service/persistence.go | 29 + pkg/service/persistence_facade.go | 21 + pkg/service/persistence_json.go | 78 + pkg/service/persistence_redis.go | 112 + pkg/service/persistence_redis_test.go | 41 + pkg/service/position.go | 101 + pkg/service/position_test.go | 61 + pkg/service/profit.go | 106 + pkg/service/profit_test.go | 41 + pkg/service/reflect.go | 254 + pkg/service/reflect_test.go | 71 + pkg/service/reward.go | 199 + pkg/service/reward_test.go | 140 + pkg/service/sync.go | 137 + pkg/service/sync_task.go | 213 + pkg/service/totp.go | 53 + pkg/service/trade.go | 453 + pkg/service/trade_test.go | 124 + pkg/service/withdraw.go | 131 + pkg/service/withdraw_test.go | 41 + pkg/sigchan/sigchan.go | 38 + pkg/slack/slacklog/logrus_look.go | 77 + pkg/slack/slackstyle/style.go | 19 + pkg/strategy/atrpin/strategy.go | 238 + pkg/strategy/audacitymaker/orderflow.go | 179 + pkg/strategy/audacitymaker/strategy.go | 135 + pkg/strategy/autoborrow/strategy.go | 681 + pkg/strategy/autobuy/strategy.go | 195 + pkg/strategy/bollgrid/strategy.go | 395 + pkg/strategy/bollmaker/doc.go | 6 + pkg/strategy/bollmaker/dynamic_spread.go | 248 + pkg/strategy/bollmaker/strategy.go | 692 + pkg/strategy/bollmaker/strategy_test.go | 69 + pkg/strategy/bollmaker/trend.go | 30 + pkg/strategy/common/callbacks.go | 38 + pkg/strategy/common/fee_budget.go | 92 + pkg/strategy/common/fee_budget_test.go | 56 + pkg/strategy/common/inventory_skew.go | 56 + pkg/strategy/common/inventory_skew_test.go | 69 + pkg/strategy/common/profit_fixer.go | 158 + pkg/strategy/common/strategy.go | 95 + pkg/strategy/common/sync.go | 105 + pkg/strategy/common/sync_test.go | 168 + pkg/strategy/convert/strategy.go | 435 + pkg/strategy/dca/strategy.go | 157 + pkg/strategy/dca2/collector.go | 203 + pkg/strategy/dca2/collector_test.go | 72 + pkg/strategy/dca2/debug.go | 34 + pkg/strategy/dca2/metrics.go | 116 + pkg/strategy/dca2/open_position.go | 131 + pkg/strategy/dca2/open_position_test.go | 95 + pkg/strategy/dca2/profit_stats.go | 96 + pkg/strategy/dca2/recover.go | 210 + pkg/strategy/dca2/recover_test.go | 173 + pkg/strategy/dca2/state.go | 244 + pkg/strategy/dca2/strategy.go | 509 + pkg/strategy/dca2/strategy_callbacks.go | 27 + pkg/strategy/dca2/sync.go | 71 + pkg/strategy/dca2/take_profit.go | 90 + pkg/strategy/dca2/take_profit_test.go | 46 + pkg/strategy/deposit2transfer/strategy.go | 284 + pkg/strategy/drift/draw.go | 176 + pkg/strategy/drift/driftma.go | 57 + pkg/strategy/drift/output.go | 18 + pkg/strategy/drift/stoploss.go | 19 + pkg/strategy/drift/stoploss_test.go | 58 + pkg/strategy/drift/strategy.go | 960 + pkg/strategy/drift/strategy_test.go | 37 + pkg/strategy/elliottwave/draw.go | 137 + pkg/strategy/elliottwave/ewo.go | 25 + pkg/strategy/elliottwave/heikinashi.go | 46 + pkg/strategy/elliottwave/output.go | 43 + pkg/strategy/elliottwave/strategy.go | 562 + pkg/strategy/emacross/strategy.go | 102 + pkg/strategy/emastop/strategy.go | 269 + pkg/strategy/etf/strategy.go | 107 + pkg/strategy/ewoDgtrd/heikinashi.go | 49 + pkg/strategy/ewoDgtrd/strategy.go | 1269 ++ .../factorzoo/factors/mom_callbacks.go | 15 + pkg/strategy/factorzoo/factors/momentum.go | 105 + .../factorzoo/factors/pmr_callbacks.go | 15 + .../factorzoo/factors/price_mean_reversion.go | 102 + .../factors/price_volume_divergence.go | 109 + .../factorzoo/factors/pvd_callbacks.go | 15 + pkg/strategy/factorzoo/factors/return_rate.go | 105 + .../factorzoo/factors/rr_callbacks.go | 15 + .../factorzoo/factors/vmom_callbacks.go | 15 + .../factorzoo/factors/volume_momentum.go | 107 + pkg/strategy/factorzoo/linear_regression.go | 194 + pkg/strategy/factorzoo/strategy.go | 133 + pkg/strategy/fixedmaker/strategy.go | 232 + pkg/strategy/flashcrash/strategy.go | 137 + pkg/strategy/fmaker/A18.go | 92 + pkg/strategy/fmaker/A2.go | 104 + pkg/strategy/fmaker/A3.go | 110 + pkg/strategy/fmaker/A34.go | 98 + pkg/strategy/fmaker/R.go | 95 + pkg/strategy/fmaker/S0.go | 90 + pkg/strategy/fmaker/S1.go | 100 + pkg/strategy/fmaker/S2.go | 96 + pkg/strategy/fmaker/S3.go | 93 + pkg/strategy/fmaker/S4.go | 90 + pkg/strategy/fmaker/S5.go | 98 + pkg/strategy/fmaker/S6.go | 100 + pkg/strategy/fmaker/S7.go | 94 + pkg/strategy/fmaker/a18_callbacks.go | 15 + pkg/strategy/fmaker/a2_callbacks.go | 15 + pkg/strategy/fmaker/a34_callbacks.go | 15 + pkg/strategy/fmaker/a3_callbacks.go | 15 + pkg/strategy/fmaker/r_callbacks.go | 15 + pkg/strategy/fmaker/s0_callbacks.go | 15 + pkg/strategy/fmaker/s1_callbacks.go | 15 + pkg/strategy/fmaker/s2_callbacks.go | 15 + pkg/strategy/fmaker/s3_callbacks.go | 15 + pkg/strategy/fmaker/s4_callbacks.go | 15 + pkg/strategy/fmaker/s5_callbacks.go | 15 + pkg/strategy/fmaker/s6_callbacks.go | 15 + pkg/strategy/fmaker/s7_callbacks.go | 15 + pkg/strategy/fmaker/strategy.go | 534 + pkg/strategy/grid/strategy.go | 636 + pkg/strategy/grid2/backtest_test.go | 184 + pkg/strategy/grid2/debug.go | 56 + pkg/strategy/grid2/grid.go | 255 + pkg/strategy/grid2/grid_dnum_test.go | 93 + pkg/strategy/grid2/grid_int64_test.go | 93 + pkg/strategy/grid2/grid_recover.go | 365 + pkg/strategy/grid2/grid_recover_test.go | 295 + pkg/strategy/grid2/grid_test.go | 267 + pkg/strategy/grid2/metrics.go | 213 + pkg/strategy/grid2/mocks/order_executor.go | 115 + pkg/strategy/grid2/pin_order_map.go | 49 + pkg/strategy/grid2/pricemap.go | 5 + pkg/strategy/grid2/profit.go | 48 + pkg/strategy/grid2/profit_fixer.go | 105 + pkg/strategy/grid2/profit_fixer_test.go | 102 + pkg/strategy/grid2/profit_stats.go | 189 + pkg/strategy/grid2/recover.go | 446 + pkg/strategy/grid2/recover_test.go | 239 + .../testcase1/closed_orders.csv | 1 + .../testcase1/open_orders.csv | 3 + .../grid2/recovery_testcase/testcase1/spec | 12 + .../recovery_testcase/testcase1/trades.csv | 1 + pkg/strategy/grid2/strategy.go | 2187 ++ pkg/strategy/grid2/strategy_callbacks.go | 45 + pkg/strategy/grid2/strategy_test.go | 1725 ++ pkg/strategy/grid2/twin_order.go | 284 + pkg/strategy/grid2/twin_order_test.go | 73 + pkg/strategy/harmonic/draw.go | 90 + pkg/strategy/harmonic/shark.go | 193 + pkg/strategy/harmonic/shark_callbacks.go | 15 + pkg/strategy/harmonic/strategy.go | 482 + pkg/strategy/irr/draw.go | 103 + pkg/strategy/irr/neg_return_rate.go | 87 + pkg/strategy/irr/nrr_callbacks.go | 15 + pkg/strategy/irr/strategy.go | 392 + pkg/strategy/kline/strategy.go | 43 + pkg/strategy/linregmaker/doc.go | 6 + pkg/strategy/linregmaker/strategy.go | 861 + pkg/strategy/liquiditymaker/generator.go | 101 + pkg/strategy/liquiditymaker/generator_test.go | 113 + pkg/strategy/liquiditymaker/strategy.go | 400 + pkg/strategy/marketcap/strategy.go | 269 + pkg/strategy/pivotshort/breaklow.go | 286 + pkg/strategy/pivotshort/failedbreakhigh.go | 404 + pkg/strategy/pivotshort/resistance.go | 207 + pkg/strategy/pivotshort/resistance_test.go | 28 + pkg/strategy/pivotshort/strategy.go | 194 + pkg/strategy/pricealert/strategy.go | 48 + pkg/strategy/pricedrop/strategy.go | 112 + pkg/strategy/random/strategy.go | 185 + .../rebalance/multi_market_strategy.go | 68 + pkg/strategy/rebalance/order_executor_map.go | 71 + pkg/strategy/rebalance/strategy.go | 303 + pkg/strategy/rsicross/strategy.go | 102 + pkg/strategy/rsmaker/strategy.go | 470 + pkg/strategy/schedule/strategy.go | 250 + pkg/strategy/scmaker/intensity.go | 44 + pkg/strategy/scmaker/strategy.go | 478 + pkg/strategy/skeleton/strategy.go | 167 + pkg/strategy/supertrend/double_dema.go | 67 + pkg/strategy/supertrend/draw.go | 90 + pkg/strategy/supertrend/linreg.go | 99 + pkg/strategy/supertrend/strategy.go | 555 + pkg/strategy/support/strategy.go | 622 + pkg/strategy/swing/strategy.go | 168 + pkg/strategy/techsignal/strategy.go | 221 + pkg/strategy/trendtrader/strategy.go | 136 + pkg/strategy/trendtrader/trend.go | 162 + pkg/strategy/tri/debug.go | 16 + pkg/strategy/tri/debug_null.go | 9 + pkg/strategy/tri/market.go | 131 + pkg/strategy/tri/path.go | 83 + pkg/strategy/tri/position.go | 139 + pkg/strategy/tri/profit.go | 60 + pkg/strategy/tri/strategy.go | 965 + pkg/strategy/tri/strategy_test.go | 222 + pkg/strategy/tri/symbols.go | 2257 ++ pkg/strategy/tri/symbols.sh | 33 + pkg/strategy/tri/utils.go | 28 + pkg/strategy/wall/strategy.go | 352 + pkg/strategy/xalign/strategy.go | 506 + pkg/strategy/xalign/strategy_test.go | 215 + pkg/strategy/xbalance/strategy.go | 368 + pkg/strategy/xbalance/strategy_test.go | 19 + pkg/strategy/xdepthmaker/profitfixer.go | 1 + pkg/strategy/xdepthmaker/state.go | 68 + pkg/strategy/xdepthmaker/strategy.go | 966 + pkg/strategy/xdepthmaker/strategy_test.go | 74 + pkg/strategy/xfixedmaker/strategy.go | 275 + pkg/strategy/xfunding/fundingfee.go | 29 + pkg/strategy/xfunding/positionstate_string.go | 26 + pkg/strategy/xfunding/profitstats.go | 54 + pkg/strategy/xfunding/strategy.go | 1235 ++ pkg/strategy/xfunding/transfer.go | 153 + pkg/strategy/xgap/strategy.go | 376 + pkg/strategy/xmaker/metrics.go | 85 + pkg/strategy/xmaker/signal_boll.go | 87 + pkg/strategy/xmaker/signal_book.go | 68 + pkg/strategy/xmaker/state.go | 68 + pkg/strategy/xmaker/strategy.go | 1411 ++ pkg/strategy/xmaker/strategy_test.go | 36 + pkg/strategy/xnav/csv.go | 1 + pkg/strategy/xnav/strategy.go | 202 + pkg/style/colors.go | 5 + pkg/style/pnl.go | 61 + pkg/style/table.go | 21 + pkg/testing/httptesting/client.go | 68 + pkg/testing/httptesting/response.go | 54 + pkg/testing/httptesting/transport.go | 98 + pkg/testing/testhelper/assert_priceside.go | 58 + pkg/testing/testhelper/number.go | 18 + pkg/testutil/auth.go | 40 + pkg/twap/stream_executor.go | 470 + pkg/twap/v2/bbomonitor.go | 53 + pkg/twap/v2/bbomonitor_callbacks.go | 17 + pkg/twap/v2/done.go | 39 + pkg/twap/v2/stream_executor.go | 617 + pkg/twap/v2/stream_executor_test.go | 316 + pkg/types/account.go | 255 + pkg/types/account_test.go | 62 + pkg/types/asset.go | 148 + pkg/types/backtest_stream.go | 20 + pkg/types/balance.go | 279 + pkg/types/balance_test.go | 98 + pkg/types/balance_type.go | 69 + pkg/types/bollinger.go | 8 + pkg/types/bookticker.go | 22 + pkg/types/channel.go | 20 + pkg/types/cross.go | 56 + pkg/types/csv.go | 7 + pkg/types/currencies.go | 54 + pkg/types/deposit.go | 83 + pkg/types/duration.go | 135 + pkg/types/duration_test.go | 55 + pkg/types/error.go | 33 + pkg/types/exchange.go | 175 + pkg/types/exchange_icon.go | 18 + pkg/types/exchange_test.go | 17 + pkg/types/filter.go | 51 + pkg/types/float64updater.go | 6 + pkg/types/float64updater_callbacks.go | 15 + pkg/types/float_map.go | 5 + pkg/types/fundingrate.go | 13 + pkg/types/futures.go | 42 + pkg/types/heikinashi_stream.go | 72 + pkg/types/indicator.go | 982 + pkg/types/indicator_test.go | 252 + pkg/types/instance.go | 5 + pkg/types/interval.go | 192 + pkg/types/interval_test.go | 26 + pkg/types/json.go | 14 + pkg/types/kline.go | 692 + pkg/types/kline_test.go | 58 + pkg/types/liquidation_info.go | 15 + pkg/types/margin.go | 166 + pkg/types/market.go | 272 + pkg/types/market_test.go | 268 + pkg/types/mocks/mock_exchange.go | 227 + pkg/types/mocks/mock_exchange_order_query.go | 71 + pkg/types/mocks/mock_exchange_public.go | 148 + .../mocks/mock_exchange_trade_history.go | 72 + pkg/types/mocks/mock_stream.go | 375 + pkg/types/omega.go | 28 + pkg/types/omega_test.go | 15 + pkg/types/order.go | 468 + pkg/types/orderbook.go | 250 + pkg/types/orderbook_test.go | 138 + pkg/types/ordermap.go | 285 + pkg/types/pca.go | 59 + pkg/types/persistence_ttl.go | 18 + pkg/types/plaintext.go | 9 + pkg/types/position.go | 673 + pkg/types/positionSide.go | 83 + pkg/types/position_metrics.go | 29 + pkg/types/position_test.go | 327 + pkg/types/premiumindex.go | 20 + pkg/types/price_type.go | 105 + pkg/types/price_volume_heartbeat.go | 45 + pkg/types/price_volume_heartbeat_test.go | 30 + pkg/types/price_volume_slice.go | 287 + pkg/types/price_volume_slice_test.go | 53 + pkg/types/profit.go | 374 + pkg/types/queue.go | 52 + pkg/types/rbtorderbook.go | 199 + pkg/types/rbtorderbook_callbacks.go | 25 + pkg/types/rbtorderbook_test.go | 78 + pkg/types/rbtree.go | 486 + pkg/types/rbtree_node.go | 33 + pkg/types/rbtree_test.go | 249 + pkg/types/reward.go | 60 + pkg/types/series.go | 123 + pkg/types/series_float64.go | 105 + pkg/types/series_float64_test.go | 18 + pkg/types/seriesbase_imp.go | 158 + pkg/types/sharpe.go | 48 + pkg/types/sharpe_test.go | 29 + pkg/types/side.go | 91 + pkg/types/sigmoid.go | 27 + pkg/types/slack.go | 7 + pkg/types/sliceorderbook.go | 213 + pkg/types/sliceorderbook_callbacks.go | 25 + pkg/types/sliceorderbook_test.go | 27 + pkg/types/sort.go | 63 + pkg/types/sort_test.go | 82 + pkg/types/sortino.go | 57 + pkg/types/sortino_test.go | 29 + pkg/types/standardstream_callbacks.go | 235 + pkg/types/strategy_status.go | 10 + pkg/types/stream.go | 589 + pkg/types/streamorderbook_callbacks.go | 25 + pkg/types/strint.go | 50 + pkg/types/syncgroup.go | 53 + pkg/types/syncgroup_test.go | 29 + pkg/types/ticker.go | 23 + pkg/types/time.go | 368 + pkg/types/time_test.go | 89 + pkg/types/trade.go | 258 + pkg/types/trade_stats.go | 427 + pkg/types/trade_stats_test.go | 59 + pkg/types/trade_test.go | 51 + pkg/types/transfer.go | 8 + pkg/types/value_map.go | 157 + pkg/types/value_map_test.go | 125 + pkg/types/withdraw.go | 145 + pkg/util/backoff/general.go | 23 + pkg/util/dir.go | 23 + pkg/util/envvars.go | 63 + pkg/util/fnv.go | 9 + pkg/util/http_response.go | 58 + pkg/util/http_response_test.go | 74 + pkg/util/json.go | 38 + pkg/util/logerr.go | 23 + pkg/util/math_test.go | 1 + pkg/util/paper_trade.go | 6 + pkg/util/pointer.go | 8 + pkg/util/pointer_18.go | 8 + pkg/util/profile.go | 42 + pkg/util/rate_limit.go | 58 + pkg/util/rate_limit_test.go | 72 + pkg/util/reonce.go | 33 + pkg/util/reonce_test.go | 39 + pkg/util/simple_args.go | 31 + pkg/util/string.go | 46 + pkg/util/string_test.go | 53 + pkg/util/templateutil/render.go | 25 + pkg/util/time.go | 16 + pkg/util/tradingutil/cancel.go | 119 + pkg/util/tradingutil/trades.go | 47 + pkg/util/tradingutil/trades_test.go | 41 + pkg/util/trylock.go | 16 + pkg/util/trylock_18.go | 14 + pkg/util/volatile_memory.go | 43 + pkg/version/dev.go | 8 + pkg/version/version.go | 8 + rockhopper_mysql.yaml | 16 + rockhopper_sqlite.yaml | 7 + scripts/bump-minor.sh | 9 + scripts/bump-patch.sh | 12 + scripts/download-dnum.sh | 40 + scripts/download.sh | 40 + scripts/goose | 33 + scripts/max.sh | 137 + scripts/maxapi.sh | 174 + scripts/release-test.sh | 12 + scripts/setup-bollgrid-dnum.sh | 109 + scripts/setup-bollgrid.sh | 117 + scripts/setup-bollmaker.sh | 185 + scripts/setup-dnum.sh | 114 + scripts/setup-grid-dnum.sh | 121 + scripts/setup-grid.sh | 122 + scripts/setup.sh | 114 + scripts/sync_time.sh | 3 + scripts/test-mysql-migrations.sh | 4 + scripts/test-sqlite3-migrations.sh | 5 + testdata/binance-markets.json | 82 + utils/changelog.sh | 58 + utils/embed/main.go | 161 + utils/generate-new-migration.sh | 4 + utils/generate-version-file.sh | 29 + utils/google-spreadsheet/main.go | 139 + 1816 files changed, 242863 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.local.example create mode 100644 .evans.toml create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 .markdownlint.yaml create mode 100644 .pre-commit-config.yaml create mode 100644 CLA.md create mode 100644 CODEOWNERS create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Procfile create mode 100644 README.md create mode 100644 README.zh_TW.md create mode 100644 app.json create mode 100644 apps/backtest-report/.eslintrc.json create mode 100644 apps/backtest-report/.gitignore create mode 100644 apps/backtest-report/README.md create mode 100644 apps/backtest-report/components/OrderListTable.tsx create mode 100644 apps/backtest-report/components/ReportDetails.tsx create mode 100644 apps/backtest-report/components/ReportNavigator.tsx create mode 100644 apps/backtest-report/components/TimeRangeSlider/components/Handle.js create mode 100644 apps/backtest-report/components/TimeRangeSlider/components/KeyboardHandle.js create mode 100644 apps/backtest-report/components/TimeRangeSlider/components/SliderRail.js create mode 100644 apps/backtest-report/components/TimeRangeSlider/components/Tick.js create mode 100644 apps/backtest-report/components/TimeRangeSlider/components/Track.js create mode 100644 apps/backtest-report/components/TimeRangeSlider/index.jsx create mode 100644 apps/backtest-report/components/TimeRangeSlider/index.scss create mode 100644 apps/backtest-report/components/TradingViewChart.tsx create mode 100644 apps/backtest-report/next-env.d.ts create mode 100644 apps/backtest-report/next.config.js create mode 100644 apps/backtest-report/package.json create mode 100644 apps/backtest-report/pages/_app.tsx create mode 100644 apps/backtest-report/pages/_document.tsx create mode 100644 apps/backtest-report/pages/api/hello.ts create mode 100644 apps/backtest-report/pages/index.tsx create mode 100644 apps/backtest-report/public/favicon.ico create mode 100644 apps/backtest-report/public/vercel.svg create mode 100644 apps/backtest-report/src/Chart.js create mode 100644 apps/backtest-report/src/utils.js create mode 100644 apps/backtest-report/styles/Home.module.css create mode 100644 apps/backtest-report/styles/globals.css create mode 100644 apps/backtest-report/tsconfig.json create mode 100644 apps/backtest-report/types/index.ts create mode 100644 apps/backtest-report/types/market.ts create mode 100644 apps/backtest-report/types/order.ts create mode 100644 apps/backtest-report/types/report.ts create mode 100644 apps/backtest-report/yarn.lock create mode 100644 apps/frontend/.gitignore create mode 100644 apps/frontend/.prettierignore create mode 100644 apps/frontend/.prettierrc.json create mode 100644 apps/frontend/README.md create mode 100644 apps/frontend/api/bbgo.ts create mode 100644 apps/frontend/components/AddExchangeSessionForm.js create mode 100644 apps/frontend/components/ConfigureDatabaseForm.js create mode 100644 apps/frontend/components/ConfigureGridStrategyForm.js create mode 100644 apps/frontend/components/ConnectWallet.js create mode 100644 apps/frontend/components/Detail.tsx create mode 100644 apps/frontend/components/ExchangeSessionTabPanel.js create mode 100644 apps/frontend/components/ReviewSessions.js create mode 100644 apps/frontend/components/ReviewStrategies.js create mode 100644 apps/frontend/components/RunningTime.tsx create mode 100644 apps/frontend/components/SaveConfigAndRestart.js create mode 100644 apps/frontend/components/SideBar.js create mode 100644 apps/frontend/components/Stats.tsx create mode 100644 apps/frontend/components/Summary.tsx create mode 100644 apps/frontend/components/SyncButton.tsx create mode 100644 apps/frontend/components/TotalAssetsDetails.js create mode 100644 apps/frontend/components/TotalAssetsPie.js create mode 100644 apps/frontend/components/TotalAssetsSummary.js create mode 100644 apps/frontend/components/TradingVolumeBar.js create mode 100644 apps/frontend/components/TradingVolumePanel.js create mode 100644 apps/frontend/hooks/useInterval.ts create mode 100644 apps/frontend/layouts/DashboardLayout.js create mode 100644 apps/frontend/layouts/PlainLayout.js create mode 100644 apps/frontend/next-env.d.ts create mode 100644 apps/frontend/next.config.js create mode 100644 apps/frontend/package.json create mode 100644 apps/frontend/pages/_app.tsx create mode 100644 apps/frontend/pages/_document.js create mode 100644 apps/frontend/pages/api/hello.js create mode 100644 apps/frontend/pages/connect/index.js create mode 100644 apps/frontend/pages/index.tsx create mode 100644 apps/frontend/pages/orders.js create mode 100644 apps/frontend/pages/setup/index.js create mode 100644 apps/frontend/pages/strategies.tsx create mode 100644 apps/frontend/pages/trades.js create mode 100644 apps/frontend/public/favicon.ico create mode 100644 apps/frontend/public/images/bch-logo.svg create mode 100644 apps/frontend/public/images/bnb-logo.svg create mode 100644 apps/frontend/public/images/btc-logo.svg create mode 100644 apps/frontend/public/images/comp-logo.svg create mode 100644 apps/frontend/public/images/dai-logo.svg create mode 100644 apps/frontend/public/images/dot-logo.svg create mode 100644 apps/frontend/public/images/eth-logo.svg create mode 100644 apps/frontend/public/images/grt-logo.svg create mode 100644 apps/frontend/public/images/link-logo.svg create mode 100644 apps/frontend/public/images/ltc-logo.svg create mode 100644 apps/frontend/public/images/max-logo.svg create mode 100644 apps/frontend/public/images/snt-logo.svg create mode 100644 apps/frontend/public/images/sxp-logo.svg create mode 100644 apps/frontend/public/images/twd-logo.svg create mode 100644 apps/frontend/public/images/usdt-logo.svg create mode 100644 apps/frontend/public/images/xrp-logo.svg create mode 100644 apps/frontend/public/images/yfi-logo.svg create mode 100644 apps/frontend/public/vercel.svg create mode 100644 apps/frontend/src/theme.js create mode 100644 apps/frontend/src/utils.js create mode 100644 apps/frontend/styles/Home.module.css create mode 100644 apps/frontend/styles/globals.css create mode 100644 apps/frontend/tsconfig.json create mode 100644 apps/frontend/yarn.lock create mode 100644 assets/bbg-256.png create mode 100644 assets/bbg-32.png create mode 100644 assets/bbg-512.png create mode 100644 assets/overview.svg create mode 100644 assets/screenshots/backtest-report.jpg create mode 100644 assets/screenshots/dashboard.jpeg create mode 100644 assets/screenshots/setup-wizard-grid.jpeg create mode 100644 assets/screenshots/setup-wizard.jpeg create mode 100644 bbgo.sql create mode 100644 charts/bbgo/.helmignore create mode 100644 charts/bbgo/Chart.yaml create mode 100644 charts/bbgo/templates/NOTES.txt create mode 100644 charts/bbgo/templates/_helpers.tpl create mode 100644 charts/bbgo/templates/configmap.yaml create mode 100644 charts/bbgo/templates/cronjob_sync.yaml create mode 100644 charts/bbgo/templates/deployment.yaml create mode 100644 charts/bbgo/templates/hpa.yaml create mode 100644 charts/bbgo/templates/ingress.yaml create mode 100644 charts/bbgo/templates/podmonitor.yaml create mode 100644 charts/bbgo/templates/service.yaml create mode 100644 charts/bbgo/templates/serviceaccount.yaml create mode 100644 charts/bbgo/templates/tests/test-connection.yaml create mode 100644 charts/bbgo/values.yaml create mode 100644 cmd/bbgo-lorca/main.go create mode 100644 cmd/bbgo-webview/main.go create mode 100644 cmd/bbgo/main.go create mode 100644 cmd/update-doc/main.go create mode 100644 codecov.yaml create mode 100644 codecov.yml create mode 100644 config/atrpin.yaml create mode 100644 config/audacitymaker.yaml create mode 100644 config/autoborrow.yaml create mode 100644 config/autobuy.yaml create mode 100644 config/backtest.yaml create mode 100644 config/binance-margin.yaml create mode 100644 config/bollgrid.yaml create mode 100644 config/bollmaker.yaml create mode 100644 config/bollmaker_optimizer.yaml create mode 100644 config/convert.yaml create mode 100644 config/dca.yaml create mode 100644 config/dca2.yaml create mode 100644 config/deposit2transfer.yaml create mode 100644 config/driftBTC.yaml create mode 100644 config/elliottwave.yaml create mode 100644 config/emacross.yaml create mode 100644 config/emastop.yaml create mode 100644 config/environment.yaml create mode 100644 config/etf.yaml create mode 100644 config/ewo_dgtrd.yaml create mode 100644 config/factorzoo.yaml create mode 100644 config/fixedmaker.yaml create mode 100644 config/flashcrash.yaml create mode 100644 config/fmaker.yaml create mode 100644 config/grid-usdttwd.yaml create mode 100644 config/grid.yaml create mode 100644 config/grid2-max.yaml create mode 100644 config/grid2.yaml create mode 100644 config/harmonic.yaml create mode 100644 config/irr.yaml create mode 100644 config/linregmaker.yaml create mode 100644 config/liquiditymaker.yaml create mode 100644 config/marketcap.yaml create mode 100644 config/max-margin.yaml create mode 100644 config/minimal.yaml create mode 100644 config/multi-session.yaml create mode 100644 config/optimizer-hyperparam-search.yaml create mode 100644 config/optimizer.yaml create mode 100644 config/pivotshort-GMTBUSD.yaml create mode 100644 config/pivotshort.yaml create mode 100644 config/pivotshort_optimizer.yaml create mode 100644 config/pricealert-tg.yaml create mode 100644 config/pricealert.yaml create mode 100644 config/pricedrop.yaml create mode 100644 config/random.yaml create mode 100644 config/rebalance.yaml create mode 100644 config/rsicross.yaml create mode 100644 config/rsmaker.yaml create mode 100644 config/schedule-USDTTWD.yaml create mode 100644 config/schedule-btcusdt.yaml create mode 100644 config/schedule-ethusdt.yaml create mode 100644 config/schedule.yaml create mode 100644 config/scmaker.yaml create mode 100644 config/skeleton.yaml create mode 100644 config/supertrend.yaml create mode 100644 config/support-margin.yaml create mode 100644 config/support.yaml create mode 100644 config/swing.yaml create mode 100644 config/sync.yaml create mode 100644 config/trendtrader.yaml create mode 100644 config/tri.yaml create mode 100644 config/wall.yaml create mode 100644 config/xalign.yaml create mode 100644 config/xbalance.yaml create mode 100644 config/xdepthmaker.yaml create mode 100644 config/xfixedmaker.yaml create mode 100644 config/xfunding.yaml create mode 100644 config/xgap.yaml create mode 100644 config/xmaker-btcusdt.yaml create mode 100644 config/xmaker-ethusdt.yaml create mode 100644 config/xmaker.yaml create mode 100644 config/xnav.yaml create mode 100644 config/xpuremaker.yaml create mode 100644 contracts/.eslintrc.js create mode 100644 contracts/.gitignore create mode 100644 contracts/.solhint.json create mode 100644 contracts/README.md create mode 100644 contracts/bsc-secret.json create mode 100644 contracts/contracts/Migrations.sol create mode 100644 contracts/contracts/Token.sol create mode 100644 contracts/contracts/child/ChildToken/ChildMintableERC20.sol create mode 100644 contracts/contracts/child/ChildToken/IChildToken.sol create mode 100644 contracts/contracts/common/AccessControlMixin.sol create mode 100644 contracts/contracts/common/ContextMixin.sol create mode 100644 contracts/contracts/common/EIP712Base.sol create mode 100644 contracts/contracts/common/Initializable.sol create mode 100644 contracts/contracts/common/NativeMetaTransaction.sol create mode 100644 contracts/contracts/common/Proxy/IERCProxy.sol create mode 100644 contracts/contracts/common/Proxy/Proxy.sol create mode 100644 contracts/contracts/common/Proxy/UpgradableProxy.sol create mode 100644 contracts/development-secret.json create mode 100644 contracts/flat/BBG.sol create mode 100644 contracts/flat/ChildERC20.sol create mode 100644 contracts/flat/ChildMintableERC20.sol create mode 100644 contracts/hardhat.config.js create mode 100644 contracts/migrations/2_deploy_child_erc20.js create mode 100644 contracts/package-lock.json create mode 100644 contracts/package.json create mode 100644 contracts/polygon-secret.json create mode 100644 contracts/test/erc20.js create mode 100644 contracts/truffle-config.js create mode 100644 data/bbgo_test.sql create mode 100644 data/binance-markets.json create mode 100644 deploy.sh create mode 100644 desktop/build-darwin.sh create mode 100644 desktop/build-osx-info-plist.sh create mode 100644 desktop/icons/icon-256.png create mode 100644 desktop/icons/icon.icns create mode 100644 desktop/icons/icon.png create mode 100644 doc/README.md create mode 100644 doc/build-from-source.md create mode 100644 doc/commands/bbgo.md create mode 100644 doc/commands/bbgo_account.md create mode 100644 doc/commands/bbgo_backtest.md create mode 100644 doc/commands/bbgo_balances.md create mode 100644 doc/commands/bbgo_build.md create mode 100644 doc/commands/bbgo_cancel-order.md create mode 100644 doc/commands/bbgo_deposits.md create mode 100644 doc/commands/bbgo_execute-order.md create mode 100644 doc/commands/bbgo_get-order.md create mode 100644 doc/commands/bbgo_hoptimize.md create mode 100644 doc/commands/bbgo_kline.md create mode 100644 doc/commands/bbgo_list-orders.md create mode 100644 doc/commands/bbgo_margin.md create mode 100644 doc/commands/bbgo_margin_interests.md create mode 100644 doc/commands/bbgo_margin_loans.md create mode 100644 doc/commands/bbgo_margin_repays.md create mode 100644 doc/commands/bbgo_market.md create mode 100644 doc/commands/bbgo_optimize.md create mode 100644 doc/commands/bbgo_orderbook.md create mode 100644 doc/commands/bbgo_orderupdate.md create mode 100644 doc/commands/bbgo_pnl.md create mode 100644 doc/commands/bbgo_run.md create mode 100644 doc/commands/bbgo_submit-order.md create mode 100644 doc/commands/bbgo_sync.md create mode 100644 doc/commands/bbgo_trades.md create mode 100644 doc/commands/bbgo_tradeupdate.md create mode 100644 doc/commands/bbgo_transfer-history.md create mode 100644 doc/commands/bbgo_userdatastream.md create mode 100644 doc/commands/bbgo_version.md create mode 100644 doc/configuration/envvars.md create mode 100644 doc/configuration/slack.md create mode 100644 doc/configuration/sync.md create mode 100644 doc/configuration/telegram.md create mode 100644 doc/deployment/helm-chart.md create mode 100644 doc/deployment/systemd.md create mode 100644 doc/development/adding-new-exchange.md create mode 100644 doc/development/frontend.md create mode 100644 doc/development/indicator-v1.md create mode 100644 doc/development/indicator.md create mode 100644 doc/development/kucoin-cli.md create mode 100644 doc/development/migration.md create mode 100644 doc/development/release-process.md create mode 100644 doc/development/series.md create mode 100644 doc/release/v1.19.3.md create mode 100644 doc/release/v1.19.4.md create mode 100644 doc/release/v1.20.0.md create mode 100644 doc/release/v1.21.0.md create mode 100644 doc/release/v1.21.1.md create mode 100644 doc/release/v1.21.2.md create mode 100644 doc/release/v1.21.3.md create mode 100644 doc/release/v1.21.4.md create mode 100644 doc/release/v1.22.0.md create mode 100644 doc/release/v1.22.1.md create mode 100644 doc/release/v1.22.2.md create mode 100644 doc/release/v1.22.3.md create mode 100644 doc/release/v1.23.0.md create mode 100644 doc/release/v1.24.0.md create mode 100644 doc/release/v1.25.0.md create mode 100644 doc/release/v1.25.1.md create mode 100644 doc/release/v1.25.2.md create mode 100644 doc/release/v1.25.3.md create mode 100644 doc/release/v1.25.4.md create mode 100644 doc/release/v1.26.0.md create mode 100644 doc/release/v1.26.1.md create mode 100644 doc/release/v1.26.3.md create mode 100644 doc/release/v1.28.0.md create mode 100644 doc/release/v1.29.0.md create mode 100644 doc/release/v1.30.0.md create mode 100644 doc/release/v1.30.1.md create mode 100644 doc/release/v1.30.2.md create mode 100644 doc/release/v1.30.3.md create mode 100644 doc/release/v1.31.0.md create mode 100644 doc/release/v1.31.1.md create mode 100644 doc/release/v1.31.2.md create mode 100644 doc/release/v1.31.3.md create mode 100644 doc/release/v1.31.4.md create mode 100644 doc/release/v1.32.0.md create mode 100644 doc/release/v1.33.0.md create mode 100644 doc/release/v1.33.1.md create mode 100644 doc/release/v1.33.2.md create mode 100644 doc/release/v1.33.3.md create mode 100644 doc/release/v1.33.4.md create mode 100644 doc/release/v1.34.0.md create mode 100644 doc/release/v1.35.0.md create mode 100644 doc/release/v1.36.0.md create mode 100644 doc/release/v1.37.0.md create mode 100644 doc/release/v1.38.0.md create mode 100644 doc/release/v1.39.0.md create mode 100644 doc/release/v1.39.1.md create mode 100644 doc/release/v1.39.2.md create mode 100644 doc/release/v1.40.1.md create mode 100644 doc/release/v1.40.2.md create mode 100644 doc/release/v1.40.3.md create mode 100644 doc/release/v1.40.4.md create mode 100644 doc/release/v1.41.0.md create mode 100644 doc/release/v1.42.0.md create mode 100644 doc/release/v1.43.0.md create mode 100644 doc/release/v1.43.1.md create mode 100644 doc/release/v1.44.0.md create mode 100644 doc/release/v1.44.1.md create mode 100644 doc/release/v1.45.0.md create mode 100644 doc/release/v1.46.0.md create mode 100644 doc/release/v1.47.0.md create mode 100644 doc/release/v1.48.0.md create mode 100644 doc/release/v1.48.1.md create mode 100644 doc/release/v1.48.2.md create mode 100644 doc/release/v1.48.3.md create mode 100644 doc/release/v1.48.4.md create mode 100644 doc/release/v1.49.0.md create mode 100644 doc/release/v1.50.0.md create mode 100644 doc/release/v1.50.1.md create mode 100644 doc/release/v1.51.0.md create mode 100644 doc/release/v1.51.1.md create mode 100644 doc/release/v1.52.0.md create mode 100644 doc/release/v1.53.0.md create mode 100644 doc/release/v1.54.0.md create mode 100644 doc/release/v1.55.0.md create mode 100644 doc/release/v1.55.1.md create mode 100644 doc/release/v1.55.2.md create mode 100644 doc/release/v1.55.3.md create mode 100644 doc/release/v1.55.4.md create mode 100644 doc/release/v1.56.0.md create mode 100644 doc/release/v1.56.1.md create mode 100644 doc/release/v1.56.2.md create mode 100644 doc/release/v1.57.0.md create mode 100644 doc/release/v1.58.0.md create mode 100644 doc/release/v1.59.0.md create mode 100644 doc/release/v1.59.1.md create mode 100644 doc/release/v1.59.2.md create mode 100644 doc/release/v1.60.0.md create mode 100644 doc/strategy/grid.md create mode 100644 doc/strategy/interaction.md create mode 100644 doc/strategy/marketcap.md create mode 100644 doc/strategy/pricealert.md create mode 100644 doc/strategy/rebalance.md create mode 100644 doc/strategy/supertrend.md create mode 100644 doc/strategy/support.md create mode 100644 doc/topics/back-testing.md create mode 100644 doc/topics/bbgo-completion.md create mode 100644 doc/topics/developing-strategy.md create mode 100644 doc/topics/dnum-binary.md create mode 100644 doc/topics/google-spreadsheet.md create mode 100644 doc/topics/grpc.md create mode 100644 doc/topics/riskcontrols.md create mode 100644 doc/topics/strategy-testing.md create mode 100644 doc/topics/twap.md create mode 100644 evans/marketDataService/subscribe_book_kucoin.json create mode 100644 evans/marketDataService/subscribe_kline_kucoin.json create mode 100644 evans/tradingService/submit_order_max.json create mode 100644 evans/userDataService/subscribe_binance.json create mode 100644 evans/userDataService/subscribe_kucoin.json create mode 100644 examples/exchange-api/binance-book/main.go create mode 100644 examples/exchange-api/binance-margin/main.go create mode 100644 examples/interact/main.go create mode 100644 examples/kucoin-accounts/main.go create mode 100644 examples/kucoin/accounts.go create mode 100644 examples/kucoin/bullet.go create mode 100644 examples/kucoin/fills.go create mode 100644 examples/kucoin/main.go create mode 100644 examples/kucoin/orderbook.go create mode 100644 examples/kucoin/orders.go create mode 100644 examples/kucoin/subaccounts.go create mode 100644 examples/kucoin/symbols.go create mode 100644 examples/kucoin/tickers.go create mode 100644 examples/kucoin/websocket.go create mode 100644 examples/max-rewards/main.go create mode 100644 examples/max-withdraw/main.go create mode 100644 examples/okex-book/main.go create mode 100644 examples/telebot/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 linode/max-grid-usdttwd.sh create mode 100644 migrations/mysql/20200721225616_trades.sql create mode 100644 migrations/mysql/20200819054742_trade_index.sql create mode 100644 migrations/mysql/20201102222546_orders.sql create mode 100644 migrations/mysql/20201103173342_trades_add_order_id.sql create mode 100644 migrations/mysql/20201105092857_trades_index_fix.sql create mode 100644 migrations/mysql/20201105093056_orders_add_index.sql create mode 100644 migrations/mysql/20201106114742_klines.sql create mode 100644 migrations/mysql/20201211175751_fix_symbol_length.sql create mode 100644 migrations/mysql/20210118163847_fix_unique_index.sql create mode 100644 migrations/mysql/20210119232826_add_margin_columns.sql create mode 100644 migrations/mysql/20210129182704_trade_price_quantity_index.sql create mode 100644 migrations/mysql/20210215203116_add_pnl_column.sql create mode 100644 migrations/mysql/20210223080622_add_rewards_table.sql create mode 100644 migrations/mysql/20210301140656_add_withdraws_table.sql create mode 100644 migrations/mysql/20210307201830_add_deposits_table.sql create mode 100644 migrations/mysql/20210416230730_klines_symbol_length.sql create mode 100644 migrations/mysql/20210421091430_increase_symbol_length.sql create mode 100644 migrations/mysql/20210421095030_increase_decimal_length.sql create mode 100644 migrations/mysql/20210531234123_add_kline_taker_buy_columns.sql create mode 100644 migrations/mysql/20211205162043_add_is_futures_column.sql create mode 100644 migrations/mysql/20211211020303_add_ftx_kline.sql create mode 100644 migrations/mysql/20211211034819_add_nav_history_details.sql create mode 100644 migrations/mysql/20211211103657_update_fee_currency_length.sql create mode 100644 migrations/mysql/20211226022411_add_kucoin_klines.sql create mode 100644 migrations/mysql/20220304153317_add_profit_table.sql create mode 100644 migrations/mysql/20220307132917_add_positions.sql create mode 100644 migrations/mysql/20220317125555_fix_trade_indexes.sql create mode 100644 migrations/mysql/20220419121046_fix_fee_column.sql create mode 100644 migrations/mysql/20220503144849_add_margin_info_to_nav.sql create mode 100644 migrations/mysql/20220504184155_fix_net_asset_column.sql create mode 100644 migrations/mysql/20220512170322_fix_profit_symbol_length.sql create mode 100644 migrations/mysql/20220520140707_kline_unique_idx.sql create mode 100644 migrations/mysql/20220531012226_margin_loans.sql create mode 100644 migrations/mysql/20220531013327_margin_repays.sql create mode 100644 migrations/mysql/20220531013542_margin_interests.sql create mode 100644 migrations/mysql/20220531015005_margin_liquidations.sql create mode 100644 migrations/mysql/20230815173104_add_bybit_klines.sql create mode 100644 migrations/mysql/20231123125402_fix_order_status_length.sql create mode 100644 migrations/mysql/20240531163411_trades_created.sql create mode 100644 migrations/sqlite3/20200721225616_trades.sql create mode 100644 migrations/sqlite3/20200819054742_trade_index.sql create mode 100644 migrations/sqlite3/20201102222546_orders.sql create mode 100644 migrations/sqlite3/20201103173342_trades_add_order_id.sql create mode 100644 migrations/sqlite3/20201105092857_trades_index_fix.sql create mode 100644 migrations/sqlite3/20201105093056_orders_add_index.sql create mode 100644 migrations/sqlite3/20201106114742_klines.sql create mode 100644 migrations/sqlite3/20210118163847_fix_unique_index.sql create mode 100644 migrations/sqlite3/20210119232826_add_margin_columns.sql create mode 100644 migrations/sqlite3/20210129182704_trade_price_quantity_index.sql create mode 100644 migrations/sqlite3/20210215203111_add_pnl_column.sql create mode 100644 migrations/sqlite3/20210223080622_add_rewards_table.sql create mode 100644 migrations/sqlite3/20210301140656_add_withdraws_table.sql create mode 100644 migrations/sqlite3/20210307201830_add_deposits_table.sql create mode 100644 migrations/sqlite3/20210531234123_add_kline_taker_buy_columns.sql create mode 100644 migrations/sqlite3/20211205162302_add_is_futures_column.sql create mode 100644 migrations/sqlite3/20211211020303_add_ftx_kline.sql create mode 100644 migrations/sqlite3/20211211034818_add_nav_history_details.sql create mode 100644 migrations/sqlite3/20211211103657_update_fee_currency_length.sql create mode 100644 migrations/sqlite3/20211226022411_add_kucoin_klines.sql create mode 100644 migrations/sqlite3/20220304153309_add_profit_table.sql create mode 100644 migrations/sqlite3/20220307132917_add_positions.sql create mode 100644 migrations/sqlite3/20220317125555_fix_trade_indexes.sql create mode 100644 migrations/sqlite3/20220419121046_fix_fee_column.sql create mode 100644 migrations/sqlite3/20220503144849_add_margin_info_to_nav.sql create mode 100644 migrations/sqlite3/20220504184155_fix_net_asset_column.sql create mode 100644 migrations/sqlite3/20220512170330_fix_profit_symbol_length.sql create mode 100644 migrations/sqlite3/20220520140707_kline_unique_idx.sql create mode 100644 migrations/sqlite3/20220531012226_margin_loans.sql create mode 100644 migrations/sqlite3/20220531013327_margin_repays.sql create mode 100644 migrations/sqlite3/20220531013541_margin_interests.sql create mode 100644 migrations/sqlite3/20220531015005_margin_liquidations.sql create mode 100644 migrations/sqlite3/20230815173104_add_bybit_klines.sql create mode 100644 migrations/sqlite3/20231123125402_fix_order_status_length.sql create mode 100644 migrations/sqlite3/20240531163411_trades_created.sql create mode 100644 pkg/accounting/cost_distribution.go create mode 100644 pkg/accounting/cost_distribution_test.go create mode 100644 pkg/accounting/pnl/avg_cost.go create mode 100644 pkg/accounting/pnl/report.go create mode 100644 pkg/accounting/testdata/btcusdt-trades.json create mode 100644 pkg/backtest/assets_dummy.go create mode 100644 pkg/backtest/dumper.go create mode 100644 pkg/backtest/dumper_test.go create mode 100644 pkg/backtest/exchange.go create mode 100644 pkg/backtest/exchange_klinec.go create mode 100644 pkg/backtest/fee.go create mode 100644 pkg/backtest/fee_test.go create mode 100644 pkg/backtest/fixture_test.go create mode 100644 pkg/backtest/manifests.go create mode 100644 pkg/backtest/matching.go create mode 100644 pkg/backtest/matching_test.go create mode 100644 pkg/backtest/priceorder.go create mode 100644 pkg/backtest/recorder.go create mode 100644 pkg/backtest/recorder_test.go create mode 100644 pkg/backtest/report.go create mode 100644 pkg/backtest/simplepricematching_callbacks.go create mode 100644 pkg/backtest/utils.go create mode 100644 pkg/bbgo/activeorderbook.go create mode 100644 pkg/bbgo/activeorderbook_callbacks.go create mode 100644 pkg/bbgo/activeorderbook_test.go create mode 100644 pkg/bbgo/backtestfeemode_enumer.go create mode 100644 pkg/bbgo/bootstrap.go create mode 100644 pkg/bbgo/builder.go create mode 100644 pkg/bbgo/config.go create mode 100644 pkg/bbgo/config_test.go create mode 100644 pkg/bbgo/consts.go create mode 100644 pkg/bbgo/doc.go create mode 100644 pkg/bbgo/environment.go create mode 100644 pkg/bbgo/envvar.go create mode 100644 pkg/bbgo/errors.go create mode 100644 pkg/bbgo/exchangeorderexecutor_callbacks.go create mode 100644 pkg/bbgo/exit.go create mode 100644 pkg/bbgo/exit_cumulated_volume_take_profit.go create mode 100644 pkg/bbgo/exit_hh_ll_stop.go create mode 100644 pkg/bbgo/exit_lower_shadow_take_profit.go create mode 100644 pkg/bbgo/exit_protective_stop_loss.go create mode 100644 pkg/bbgo/exit_roi_stop_loss.go create mode 100644 pkg/bbgo/exit_roi_take_profit.go create mode 100644 pkg/bbgo/exit_support_take_profit.go create mode 100644 pkg/bbgo/exit_test.go create mode 100644 pkg/bbgo/exit_trailing_stop.go create mode 100644 pkg/bbgo/exit_trailing_stop_test.go create mode 100644 pkg/bbgo/graceful_shutdown.go create mode 100644 pkg/bbgo/gracefulshutdown_callbacks.go create mode 100644 pkg/bbgo/indicator_set.go create mode 100644 pkg/bbgo/indicator_set_test.go create mode 100644 pkg/bbgo/interact.go create mode 100644 pkg/bbgo/interact_modify.go create mode 100644 pkg/bbgo/interact_test.go create mode 100644 pkg/bbgo/isolation.go create mode 100644 pkg/bbgo/isolation_test.go create mode 100644 pkg/bbgo/log.go create mode 100644 pkg/bbgo/marketdatastore.go create mode 100644 pkg/bbgo/marketdatastore_callbacks.go create mode 100644 pkg/bbgo/metrics.go create mode 100644 pkg/bbgo/mocks/mock_order_executor_extended.go create mode 100644 pkg/bbgo/moving_average_settings.go create mode 100644 pkg/bbgo/notification.go create mode 100644 pkg/bbgo/order_execution.go create mode 100644 pkg/bbgo/order_executor_fast.go create mode 100644 pkg/bbgo/order_executor_general.go create mode 100644 pkg/bbgo/order_executor_simple.go create mode 100644 pkg/bbgo/order_processor.go create mode 100644 pkg/bbgo/order_processor_test.go create mode 100644 pkg/bbgo/persistence.go create mode 100644 pkg/bbgo/persistence_test.go create mode 100644 pkg/bbgo/profitstats.go create mode 100644 pkg/bbgo/quantity_amount.go create mode 100644 pkg/bbgo/quota.go create mode 100644 pkg/bbgo/reflect.go create mode 100644 pkg/bbgo/reflect_test.go create mode 100644 pkg/bbgo/reporter.go create mode 100644 pkg/bbgo/risk.go create mode 100644 pkg/bbgo/risk_controls.go create mode 100644 pkg/bbgo/risk_test.go create mode 100644 pkg/bbgo/scale.go create mode 100644 pkg/bbgo/scale_test.go create mode 100644 pkg/bbgo/serialmarketdatastore.go create mode 100644 pkg/bbgo/session.go create mode 100644 pkg/bbgo/session_test.go create mode 100644 pkg/bbgo/source.go create mode 100644 pkg/bbgo/source_test.go create mode 100644 pkg/bbgo/standard_indicator_set.go create mode 100644 pkg/bbgo/stop_ema.go create mode 100644 pkg/bbgo/strategy_controller.go create mode 100644 pkg/bbgo/strategy_test.go create mode 100644 pkg/bbgo/strategycontroller_callbacks.go create mode 100644 pkg/bbgo/string.go create mode 100644 pkg/bbgo/testdata/backtest.yaml create mode 100644 pkg/bbgo/testdata/notification.yaml create mode 100644 pkg/bbgo/testdata/order_executor.yaml create mode 100644 pkg/bbgo/testdata/persistence.yaml create mode 100644 pkg/bbgo/testdata/strategy.yaml create mode 100644 pkg/bbgo/time.go create mode 100644 pkg/bbgo/trader.go create mode 100644 pkg/bbgo/trader_test.go create mode 100644 pkg/bbgo/trend_ema.go create mode 100644 pkg/bbgo/trend_ema_test.go create mode 100644 pkg/bbgo/wrapper.go create mode 100644 pkg/cache/cache.go create mode 100644 pkg/cache/cache_test.go create mode 100644 pkg/cache/home.go create mode 100644 pkg/cmd/account.go create mode 100644 pkg/cmd/backtest.go create mode 100644 pkg/cmd/balances.go create mode 100644 pkg/cmd/build.go create mode 100644 pkg/cmd/cancel.go create mode 100644 pkg/cmd/cmdutil/exchange.go create mode 100644 pkg/cmd/cmdutil/flags.go create mode 100644 pkg/cmd/cmdutil/signal.go create mode 100644 pkg/cmd/deposit.go create mode 100644 pkg/cmd/exchangetest.go create mode 100644 pkg/cmd/execute_order.go create mode 100644 pkg/cmd/hoptimize.go create mode 100644 pkg/cmd/import.go create mode 100644 pkg/cmd/kline.go create mode 100644 pkg/cmd/margin.go create mode 100644 pkg/cmd/market.go create mode 100644 pkg/cmd/optimize.go create mode 100644 pkg/cmd/orderbook.go create mode 100644 pkg/cmd/orders.go create mode 100644 pkg/cmd/pnl.go create mode 100644 pkg/cmd/root.go create mode 100644 pkg/cmd/run.go create mode 100644 pkg/cmd/strategy/builtin.go create mode 100644 pkg/cmd/sync.go create mode 100644 pkg/cmd/trades.go create mode 100644 pkg/cmd/transfer.go create mode 100644 pkg/cmd/userdatastream.go create mode 100644 pkg/cmd/utils.go create mode 100644 pkg/cmd/version.go create mode 100644 pkg/core/converter.go create mode 100644 pkg/core/converter_test.go create mode 100644 pkg/core/orderstore.go create mode 100644 pkg/core/tradecollector.go create mode 100644 pkg/core/tradecollector_callbacks.go create mode 100644 pkg/core/tradecollector_test.go create mode 100644 pkg/core/tradestore.go create mode 100644 pkg/core/tradestore_test.go create mode 100644 pkg/data/tsv/writer.go create mode 100644 pkg/datasource/coinmarketcap/datasource.go create mode 100644 pkg/datasource/coinmarketcap/v1/client.go create mode 100644 pkg/datasource/coinmarketcap/v1/listings.go create mode 100644 pkg/datasource/coinmarketcap/v1/listings_historical_request_requestgen.go create mode 100644 pkg/datasource/coinmarketcap/v1/listings_latest_request_requestgen.go create mode 100644 pkg/datasource/coinmarketcap/v1/listings_new_request_requestgen.go create mode 100644 pkg/datasource/coinmarketcap/v1/types.go create mode 100644 pkg/datasource/glassnode/datasource.go create mode 100644 pkg/datasource/glassnode/glassnodeapi/client.go create mode 100644 pkg/datasource/glassnode/glassnodeapi/request.go create mode 100644 pkg/datasource/glassnode/glassnodeapi/request_requestgen.go create mode 100644 pkg/datasource/glassnode/glassnodeapi/types.go create mode 100644 pkg/datasource/glassnode/types.go create mode 100644 pkg/datasource/wise/README.md create mode 100644 pkg/datasource/wise/client.go create mode 100644 pkg/datasource/wise/group.go create mode 100644 pkg/datasource/wise/rate.go create mode 100644 pkg/datasource/wise/rate_request.go create mode 100644 pkg/datasource/wise/rate_request_requestgen.go create mode 100644 pkg/datasource/wise/time.go create mode 100644 pkg/datatype/bools/slice.go create mode 100644 pkg/datatype/floats/funcs.go create mode 100644 pkg/datatype/floats/funcs_test.go create mode 100644 pkg/datatype/floats/map.go create mode 100644 pkg/datatype/floats/pivot.go create mode 100644 pkg/datatype/floats/pivot_test.go create mode 100644 pkg/datatype/floats/slice.go create mode 100644 pkg/datatype/floats/slice_test.go create mode 100644 pkg/datatype/string_slice.go create mode 100644 pkg/depth/buffer.go create mode 100644 pkg/depth/buffer_callbacks.go create mode 100644 pkg/depth/buffer_test.go create mode 100644 pkg/dynamic/call.go create mode 100644 pkg/dynamic/call_test.go create mode 100644 pkg/dynamic/can.go create mode 100644 pkg/dynamic/field.go create mode 100644 pkg/dynamic/field_test.go create mode 100644 pkg/dynamic/id.go create mode 100644 pkg/dynamic/inject.go create mode 100644 pkg/dynamic/inject_test.go create mode 100644 pkg/dynamic/iterate.go create mode 100644 pkg/dynamic/iterate_test.go create mode 100644 pkg/dynamic/merge.go create mode 100644 pkg/dynamic/merge_test.go create mode 100644 pkg/dynamic/print_config.go create mode 100644 pkg/dynamic/print_strategy.go create mode 100644 pkg/dynamic/typevalue.go create mode 100644 pkg/exchange/batch/batch_test.go create mode 100644 pkg/exchange/batch/closedorders.go create mode 100644 pkg/exchange/batch/deposit.go create mode 100644 pkg/exchange/batch/funding_fee.go create mode 100644 pkg/exchange/batch/kline.go create mode 100644 pkg/exchange/batch/margin_interest.go create mode 100644 pkg/exchange/batch/margin_liquidation.go create mode 100644 pkg/exchange/batch/margin_loan.go create mode 100644 pkg/exchange/batch/margin_repay.go create mode 100644 pkg/exchange/batch/option.go create mode 100644 pkg/exchange/batch/reward.go create mode 100644 pkg/exchange/batch/time_range_query.go create mode 100644 pkg/exchange/batch/time_range_query_test.go create mode 100644 pkg/exchange/batch/trade.go create mode 100644 pkg/exchange/batch/trade_test.go create mode 100644 pkg/exchange/batch/withdraw.go create mode 100644 pkg/exchange/batch/withdraw_test.go create mode 100644 pkg/exchange/binance/binanceapi/alias.go create mode 100644 pkg/exchange/binance/binanceapi/cancel_replace_request.go create mode 100644 pkg/exchange/binance/binanceapi/cancel_replace_spot_order_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/client.go create mode 100644 pkg/exchange/binance/binanceapi/client_test.go create mode 100644 pkg/exchange/binance/binanceapi/futures_change_initial_leverage_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_change_initial_leverage_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_change_multi_assets_mode_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_change_multi_assets_mode_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_client.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_account_balance_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_account_balance_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_account_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_account_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_global_long_short_account_ratio.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_income_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_income_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_multi_assets_mode_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_multi_assets_mode_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_open_interest.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_open_interest_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_open_interest_statistics.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_open_interest_statistics_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_position_risks_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_position_risks_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_taker_buy_sell_volume.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_top_trader_long_short_account_ratio.go create mode 100644 pkg/exchange/binance/binanceapi/futures_get_top_trader_long_short_position_ratio.go create mode 100644 pkg/exchange/binance/binanceapi/futures_global_long_short_account_ratio_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_taker_buy_sell_volume_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_top_trader_long_short_account_ratio_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_top_trader_long_short_position_ratio_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/futures_transfer_request.go create mode 100644 pkg/exchange/binance/binanceapi/futures_transfer_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_api_referral_if_new_user_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_api_referral_if_new_user_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_deposit_address_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_deposit_address_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_deposit_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_deposit_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_depth_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_depth_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_historical_trades_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_historical_trades_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_borrow_repay_history_request_test.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_interest_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_interest_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_interest_history_request_test.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_interest_rate_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_interest_rate_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_liquidation_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_liquidation_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_max_borrowable_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_max_borrowable_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_trades_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_margin_trades_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_my_trades_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_my_trades_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_spot_rebate_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_spot_rebate_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_trade_fee_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_trade_fee_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/get_withdraw_history_request.go create mode 100644 pkg/exchange/binance/binanceapi/get_withdraw_history_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/page.go create mode 100644 pkg/exchange/binance/binanceapi/place_margin_order_request.go create mode 100644 pkg/exchange/binance/binanceapi/place_margin_order_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/rows.go create mode 100644 pkg/exchange/binance/binanceapi/transfer_asset_request.go create mode 100644 pkg/exchange/binance/binanceapi/transfer_asset_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/transfertype_string.go create mode 100644 pkg/exchange/binance/binanceapi/withdraw_request.go create mode 100644 pkg/exchange/binance/binanceapi/withdraw_request_requestgen.go create mode 100644 pkg/exchange/binance/binanceapi/withdrawstatus_string.go create mode 100644 pkg/exchange/binance/cancel_replace.go create mode 100644 pkg/exchange/binance/convert.go create mode 100644 pkg/exchange/binance/convert_futures.go create mode 100644 pkg/exchange/binance/convert_margin.go create mode 100644 pkg/exchange/binance/exchange.go create mode 100644 pkg/exchange/binance/exchange_test.go create mode 100644 pkg/exchange/binance/futures.go create mode 100644 pkg/exchange/binance/historical_trades.go create mode 100644 pkg/exchange/binance/margin_history.go create mode 100644 pkg/exchange/binance/parse.go create mode 100644 pkg/exchange/binance/parse_test.go create mode 100644 pkg/exchange/binance/reward.go create mode 100644 pkg/exchange/binance/stream.go create mode 100644 pkg/exchange/binance/stream_callbacks.go create mode 100644 pkg/exchange/binance/ticker_test.go create mode 100644 pkg/exchange/bitget/bitgetapi/client.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/cancel_order_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/client.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/client_test.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_account_assets_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_account_assets_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_history_orders_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_history_orders_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_history_orders_request_test.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_k_line.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_k_line_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_symbols_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_symbols_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_tickers_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_tickers_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_trade_fills.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_trade_fills_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_unfilled_orders_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/get_unfilled_orders_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/place_order_request.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/place_order_request_requestgen.go create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/cancel_order_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_account_assets_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_history_orders_request_market_buy.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_k_line_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_symbols_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_ticker_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_tickers_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_trade_fills_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_limit_order.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_buy_order.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/get_unfilled_orders_request_market_sell_order.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/place_order_request.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/testdata/request_error.json create mode 100644 pkg/exchange/bitget/bitgetapi/v2/types.go create mode 100644 pkg/exchange/bitget/convert.go create mode 100644 pkg/exchange/bitget/convert_test.go create mode 100644 pkg/exchange/bitget/debug.go create mode 100644 pkg/exchange/bitget/exchange.go create mode 100644 pkg/exchange/bitget/exchange_test.go create mode 100644 pkg/exchange/bitget/stream.go create mode 100644 pkg/exchange/bitget/stream_callbacks.go create mode 100644 pkg/exchange/bitget/stream_test.go create mode 100644 pkg/exchange/bitget/types.go create mode 100644 pkg/exchange/bitget/types_test.go create mode 100644 pkg/exchange/bybit/bybitapi/cancel_order_request.go create mode 100644 pkg/exchange/bybit/bybitapi/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/client.go create mode 100644 pkg/exchange/bybit/bybitapi/client_test.go create mode 100644 pkg/exchange/bybit/bybitapi/get_account_info_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_account_info_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_fee_rates_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_fee_rates_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_instruments_info_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_instruments_info_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_k_lines_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_k_lines_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_k_lines_request_test.go create mode 100644 pkg/exchange/bybit/bybitapi/get_open_orders_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_open_orders_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_order_histories_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_order_histories_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_tickers_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_tickers_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/get_wallet_balances_request.go create mode 100644 pkg/exchange/bybit/bybitapi/get_wallet_balances_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/place_order_request.go create mode 100644 pkg/exchange/bybit/bybitapi/place_order_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/types.go create mode 100644 pkg/exchange/bybit/bybitapi/types_test.go create mode 100644 pkg/exchange/bybit/bybitapi/v3/client.go create mode 100644 pkg/exchange/bybit/bybitapi/v3/client_test.go create mode 100644 pkg/exchange/bybit/bybitapi/v3/get_trades_request.go create mode 100644 pkg/exchange/bybit/bybitapi/v3/get_trades_request_requestgen.go create mode 100644 pkg/exchange/bybit/bybitapi/v3/types.go create mode 100644 pkg/exchange/bybit/convert.go create mode 100644 pkg/exchange/bybit/convert_test.go create mode 100644 pkg/exchange/bybit/exchange.go create mode 100644 pkg/exchange/bybit/market_info_poller.go create mode 100644 pkg/exchange/bybit/market_info_poller_test.go create mode 100644 pkg/exchange/bybit/mocks/stream.go create mode 100644 pkg/exchange/bybit/stream.go create mode 100644 pkg/exchange/bybit/stream_callbacks.go create mode 100644 pkg/exchange/bybit/stream_test.go create mode 100644 pkg/exchange/bybit/types.go create mode 100644 pkg/exchange/bybit/types_test.go create mode 100644 pkg/exchange/factory.go create mode 100644 pkg/exchange/kucoin/convert.go create mode 100644 pkg/exchange/kucoin/exchange.go create mode 100644 pkg/exchange/kucoin/generate_symbol_map.go create mode 100644 pkg/exchange/kucoin/kucoinapi/account.go create mode 100644 pkg/exchange/kucoin/kucoinapi/bullet.go create mode 100644 pkg/exchange/kucoin/kucoinapi/cancel_all_order_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/client.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_account_request.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_account_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_all_tickers_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_fills_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_k_lines_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_order_book_level_2_depth_100_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_order_book_level_2_depth_20_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_order_book_level_2_depth_all_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_private_bullet_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_public_bullet_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/get_ticker_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_accounts_request.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_accounts_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_history_orders_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_orders_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_sub_accounts_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/list_symbols_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/marketdata.go create mode 100644 pkg/exchange/kucoin/kucoinapi/place_order_request_requestgen.go create mode 100644 pkg/exchange/kucoin/kucoinapi/trade.go create mode 100644 pkg/exchange/kucoin/kucoinapi/types.go create mode 100644 pkg/exchange/kucoin/parse.go create mode 100644 pkg/exchange/kucoin/stream.go create mode 100644 pkg/exchange/kucoin/stream_callbacks.go create mode 100644 pkg/exchange/kucoin/symbols.go create mode 100644 pkg/exchange/kucoin/testdata/ack.json create mode 100644 pkg/exchange/kucoin/testdata/btc-01-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/btc-02-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/btc-03-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/btc-04-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-01-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-02-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-03-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-04-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-05-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-06-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-07-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-08-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-09-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-10-trade-orders.json create mode 100644 pkg/exchange/kucoin/testdata/cro-11-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/cro-12-account-balance.json create mode 100644 pkg/exchange/kucoin/testdata/welcome.json create mode 100644 pkg/exchange/kucoin/websocket.go create mode 100644 pkg/exchange/max/client_order_id.go create mode 100644 pkg/exchange/max/convert.go create mode 100644 pkg/exchange/max/convert_test.go create mode 100644 pkg/exchange/max/exchange.go create mode 100644 pkg/exchange/max/margin.go create mode 100644 pkg/exchange/max/maxapi/account.go create mode 100644 pkg/exchange/max/maxapi/account_test.go create mode 100644 pkg/exchange/max/maxapi/auth.go create mode 100644 pkg/exchange/max/maxapi/cancel_order_request.go create mode 100644 pkg/exchange/max/maxapi/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/create_order_request.go create mode 100644 pkg/exchange/max/maxapi/create_order_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_account_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_accounts_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_deposit_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_k_lines_request.go create mode 100644 pkg/exchange/max/maxapi/get_k_lines_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_markets_request.go create mode 100644 pkg/exchange/max/maxapi/get_markets_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_rewards_of_type_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_rewards_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_ticker_request.go create mode 100644 pkg/exchange/max/maxapi/get_ticker_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_tickers_request.go create mode 100644 pkg/exchange/max/maxapi/get_tickers_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_timestamp_request.go create mode 100644 pkg/exchange/max/maxapi/get_timestamp_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_vip_level_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_withdraw_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/get_withdrawal_addresses_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/order.go create mode 100644 pkg/exchange/max/maxapi/order_test.go create mode 100644 pkg/exchange/max/maxapi/public.go create mode 100644 pkg/exchange/max/maxapi/public_parser.go create mode 100644 pkg/exchange/max/maxapi/public_test.go create mode 100644 pkg/exchange/max/maxapi/restapi.go create mode 100644 pkg/exchange/max/maxapi/reward.go create mode 100644 pkg/exchange/max/maxapi/reward_test.go create mode 100644 pkg/exchange/max/maxapi/trade.go create mode 100644 pkg/exchange/max/maxapi/userdata.go create mode 100644 pkg/exchange/max/maxapi/userdata_test.go create mode 100644 pkg/exchange/max/maxapi/v3/cancel_order_request.go create mode 100644 pkg/exchange/max/maxapi/v3/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/cancel_wallet_order_all_request.go create mode 100644 pkg/exchange/max/maxapi/v3/cancel_wallet_order_all_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/create_wallet_order_request.go create mode 100644 pkg/exchange/max/maxapi/v3/create_wallet_order_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_ad_ratio_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_ad_ratio_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_borrowing_limits_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_interest_history_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_interest_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_interest_rates_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_interest_rates_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_liquidation_history_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_liquidation_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_loan_history_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_loan_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_repayment_history_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_margin_repayment_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_order_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_order_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_order_trades_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_order_trades_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_accounts_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_accounts_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_closed_orders_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_closed_orders_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_open_orders_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_open_orders_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_order_history_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_order_history_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_trades_request.go create mode 100644 pkg/exchange/max/maxapi/v3/get_wallet_trades_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/margin.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_loan_request.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_loan_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_repay_request.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_repay_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_transfer_request.go create mode 100644 pkg/exchange/max/maxapi/v3/margin_transfer_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/v3/order.go create mode 100644 pkg/exchange/max/maxapi/v3/trade.go create mode 100644 pkg/exchange/max/maxapi/websocket.go create mode 100644 pkg/exchange/max/maxapi/withdrawal.go create mode 100644 pkg/exchange/max/maxapi/withdrawal_request_requestgen.go create mode 100644 pkg/exchange/max/maxapi/withdrawal_test.go create mode 100644 pkg/exchange/max/stream.go create mode 100644 pkg/exchange/max/stream_callbacks.go create mode 100644 pkg/exchange/max/ticker_test.go create mode 100644 pkg/exchange/okex/convert.go create mode 100644 pkg/exchange/okex/convert_test.go create mode 100644 pkg/exchange/okex/exchange.go create mode 100644 pkg/exchange/okex/exchange_test.go create mode 100644 pkg/exchange/okex/gensymbols.go create mode 100644 pkg/exchange/okex/kline_stream.go create mode 100644 pkg/exchange/okex/klinestream_callbacks.go create mode 100644 pkg/exchange/okex/okexapi/cancel_order_request.go create mode 100644 pkg/exchange/okex/okexapi/cancel_order_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/client.go create mode 100644 pkg/exchange/okex/okexapi/client_test.go create mode 100644 pkg/exchange/okex/okexapi/get_account_info_request.go create mode 100644 pkg/exchange/okex/okexapi/get_account_info_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_candles_request.go create mode 100644 pkg/exchange/okex/okexapi/get_candles_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_instruments_info_request.go create mode 100644 pkg/exchange/okex/okexapi/get_instruments_info_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_open_orders_request.go create mode 100644 pkg/exchange/okex/okexapi/get_open_orders_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_order_history_request.go create mode 100644 pkg/exchange/okex/okexapi/get_order_history_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_three_days_transaction_history_request.go create mode 100644 pkg/exchange/okex/okexapi/get_three_days_transaction_history_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_ticker_request.go create mode 100644 pkg/exchange/okex/okexapi/get_ticker_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_tickers_request.go create mode 100644 pkg/exchange/okex/okexapi/get_tickers_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/get_transaction_history_request.go create mode 100644 pkg/exchange/okex/okexapi/get_transaction_history_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/market.go create mode 100644 pkg/exchange/okex/okexapi/place_order_request.go create mode 100644 pkg/exchange/okex/okexapi/place_order_request_requestgen.go create mode 100644 pkg/exchange/okex/okexapi/public.go create mode 100644 pkg/exchange/okex/okexapi/testdata/get_three_days_transaction_history_request.json create mode 100644 pkg/exchange/okex/okexapi/testdata/get_transaction_history_request.json create mode 100644 pkg/exchange/okex/okexapi/trade.go create mode 100644 pkg/exchange/okex/parse.go create mode 100644 pkg/exchange/okex/parse_test.go create mode 100644 pkg/exchange/okex/query_closed_orders_test.go create mode 100644 pkg/exchange/okex/query_kline_test.go create mode 100644 pkg/exchange/okex/query_order_test.go create mode 100644 pkg/exchange/okex/query_order_trades_test.go create mode 100644 pkg/exchange/okex/query_trades_test.go create mode 100644 pkg/exchange/okex/stream.go create mode 100644 pkg/exchange/okex/stream_callbacks.go create mode 100644 pkg/exchange/okex/stream_test.go create mode 100644 pkg/exchange/okex/symbols.go create mode 100644 pkg/exchange/okex/types.go create mode 100644 pkg/exchange/retry/account.go create mode 100644 pkg/exchange/retry/order.go create mode 100644 pkg/exchange/retry/ticker.go create mode 100644 pkg/exchange/retry/trade.go create mode 100644 pkg/exchange/util.go create mode 100644 pkg/fixedpoint/const.go create mode 100644 pkg/fixedpoint/convert.go create mode 100644 pkg/fixedpoint/convert_test.go create mode 100644 pkg/fixedpoint/count.go create mode 100644 pkg/fixedpoint/dec.go create mode 100644 pkg/fixedpoint/dec_dnum_test.go create mode 100644 pkg/fixedpoint/dec_legacy_test.go create mode 100644 pkg/fixedpoint/dec_test.go create mode 100644 pkg/fixedpoint/div128.go create mode 100644 pkg/fixedpoint/filter.go create mode 100644 pkg/fixedpoint/helpers.go create mode 100644 pkg/fixedpoint/reduce.go create mode 100644 pkg/fixedpoint/reduce_test.go create mode 100644 pkg/fixedpoint/slice.go create mode 100644 pkg/fixedpoint/slice_test.go create mode 100644 pkg/grpc/convert.go create mode 100644 pkg/grpc/server.go create mode 100644 pkg/indicator/ad.go create mode 100644 pkg/indicator/ad_callbacks.go create mode 100644 pkg/indicator/alma.go create mode 100644 pkg/indicator/alma_callbacks.go create mode 100644 pkg/indicator/alma_test.go create mode 100644 pkg/indicator/atr.go create mode 100644 pkg/indicator/atr_callbacks.go create mode 100644 pkg/indicator/atr_test.go create mode 100644 pkg/indicator/atrp.go create mode 100644 pkg/indicator/atrp_callbacks.go create mode 100644 pkg/indicator/boll.go create mode 100644 pkg/indicator/boll_callbacks.go create mode 100644 pkg/indicator/boll_test.go create mode 100644 pkg/indicator/ca_callbacks.go create mode 100644 pkg/indicator/cci.go create mode 100644 pkg/indicator/cci_callbacks.go create mode 100644 pkg/indicator/cci_test.go create mode 100644 pkg/indicator/cma.go create mode 100644 pkg/indicator/const.go create mode 100644 pkg/indicator/dema.go create mode 100644 pkg/indicator/dema_callbacks.go create mode 100644 pkg/indicator/dema_test.go create mode 100644 pkg/indicator/dmi.go create mode 100644 pkg/indicator/dmi_callbacks.go create mode 100644 pkg/indicator/dmi_test.go create mode 100644 pkg/indicator/drift.go create mode 100644 pkg/indicator/drift_callbacks.go create mode 100644 pkg/indicator/drift_test.go create mode 100644 pkg/indicator/emv.go create mode 100644 pkg/indicator/emv_callbacks.go create mode 100644 pkg/indicator/emv_test.go create mode 100644 pkg/indicator/ewma.go create mode 100644 pkg/indicator/ewma_callbacks.go create mode 100644 pkg/indicator/ewma_test.go create mode 100644 pkg/indicator/fisher.go create mode 100644 pkg/indicator/fishertransform_callbacks.go create mode 100644 pkg/indicator/ghfilter.go create mode 100644 pkg/indicator/ghfilter_callbacks.go create mode 100644 pkg/indicator/ghfilter_test.go create mode 100644 pkg/indicator/gma.go create mode 100644 pkg/indicator/gma_callbacks.go create mode 100644 pkg/indicator/gma_test.go create mode 100644 pkg/indicator/hull.go create mode 100644 pkg/indicator/hull_callbacks.go create mode 100644 pkg/indicator/hull_test.go create mode 100644 pkg/indicator/interface.go create mode 100644 pkg/indicator/kalmanfilter.go create mode 100644 pkg/indicator/kalmanfilter_callbacks.go create mode 100644 pkg/indicator/kalmanfilter_test.go create mode 100644 pkg/indicator/klingeroscillator.go create mode 100644 pkg/indicator/klingeroscillator_callbacks.go create mode 100644 pkg/indicator/klingeroscillator_test.go create mode 100644 pkg/indicator/line.go create mode 100644 pkg/indicator/linreg.go create mode 100644 pkg/indicator/linreg_callbacks.go create mode 100644 pkg/indicator/macd.go create mode 100644 pkg/indicator/macd_test.go create mode 100644 pkg/indicator/macdlegacy_callbacks.go create mode 100644 pkg/indicator/obv.go create mode 100644 pkg/indicator/obv_callbacks.go create mode 100644 pkg/indicator/obv_test.go create mode 100644 pkg/indicator/pivot.go create mode 100644 pkg/indicator/pivot_callbacks.go create mode 100644 pkg/indicator/pivothigh.go create mode 100644 pkg/indicator/pivothigh_callbacks.go create mode 100644 pkg/indicator/pivotlow.go create mode 100644 pkg/indicator/pivotlow_callbacks.go create mode 100644 pkg/indicator/pivotlow_test.go create mode 100644 pkg/indicator/psar.go create mode 100644 pkg/indicator/psar_callbacks.go create mode 100644 pkg/indicator/psar_test.go create mode 100644 pkg/indicator/rma.go create mode 100644 pkg/indicator/rma_callbacks.go create mode 100644 pkg/indicator/rma_test.go create mode 100644 pkg/indicator/rsi.go create mode 100644 pkg/indicator/rsi_callbacks.go create mode 100644 pkg/indicator/rsi_test.go create mode 100644 pkg/indicator/sma.go create mode 100644 pkg/indicator/sma_callbacks.go create mode 100644 pkg/indicator/sma_test.go create mode 100644 pkg/indicator/ssf.go create mode 100644 pkg/indicator/ssf_callbacks.go create mode 100644 pkg/indicator/ssf_test.go create mode 100644 pkg/indicator/stddev.go create mode 100644 pkg/indicator/stddev_callbacks.go create mode 100644 pkg/indicator/stoch.go create mode 100644 pkg/indicator/stoch_callbacks.go create mode 100644 pkg/indicator/stoch_test.go create mode 100644 pkg/indicator/supertrend.go create mode 100644 pkg/indicator/supertrendPivot.go create mode 100644 pkg/indicator/supertrendPivot_callbacks.go create mode 100644 pkg/indicator/supertrend_callbacks.go create mode 100644 pkg/indicator/tema.go create mode 100644 pkg/indicator/tema_callbacks.go create mode 100644 pkg/indicator/tema_test.go create mode 100644 pkg/indicator/till.go create mode 100644 pkg/indicator/till_callbacks.go create mode 100644 pkg/indicator/till_test.go create mode 100644 pkg/indicator/tma.go create mode 100644 pkg/indicator/tma_callbacks.go create mode 100644 pkg/indicator/tsi.go create mode 100644 pkg/indicator/tsi_callbacks.go create mode 100644 pkg/indicator/tsi_test.go create mode 100644 pkg/indicator/utBotAlert.go create mode 100644 pkg/indicator/utBotAlert_callbacks.go create mode 100644 pkg/indicator/util.go create mode 100644 pkg/indicator/v2/adx.go create mode 100644 pkg/indicator/v2/adx_test.go create mode 100644 pkg/indicator/v2/atr.go create mode 100644 pkg/indicator/v2/atr_test.go create mode 100644 pkg/indicator/v2/atrp.go create mode 100644 pkg/indicator/v2/boll.go create mode 100644 pkg/indicator/v2/cci.go create mode 100644 pkg/indicator/v2/cci_test.go create mode 100644 pkg/indicator/v2/cma.go create mode 100644 pkg/indicator/v2/const.go create mode 100644 pkg/indicator/v2/cross.go create mode 100644 pkg/indicator/v2/ewma.go create mode 100644 pkg/indicator/v2/keltner.go create mode 100644 pkg/indicator/v2/klines.go create mode 100644 pkg/indicator/v2/klinestream_callbacks.go create mode 100644 pkg/indicator/v2/macd.go create mode 100644 pkg/indicator/v2/macd_test.go create mode 100644 pkg/indicator/v2/multiply.go create mode 100644 pkg/indicator/v2/pivothigh.go create mode 100644 pkg/indicator/v2/pivotlow.go create mode 100644 pkg/indicator/v2/price.go create mode 100644 pkg/indicator/v2/rma.go create mode 100644 pkg/indicator/v2/rma_test.go create mode 100644 pkg/indicator/v2/rsi.go create mode 100644 pkg/indicator/v2/rsi_test.go create mode 100644 pkg/indicator/v2/sma.go create mode 100644 pkg/indicator/v2/sma_test.go create mode 100644 pkg/indicator/v2/smma.go create mode 100644 pkg/indicator/v2/smma_test.go create mode 100644 pkg/indicator/v2/stddev.go create mode 100644 pkg/indicator/v2/stoch.go create mode 100644 pkg/indicator/v2/stoch_test.go create mode 100644 pkg/indicator/v2/stochstream_callbacks.go create mode 100644 pkg/indicator/v2/subtract.go create mode 100644 pkg/indicator/v2/subtract_test.go create mode 100644 pkg/indicator/v2/tr.go create mode 100644 pkg/indicator/v2/tr_test.go create mode 100644 pkg/indicator/vidya.go create mode 100644 pkg/indicator/vidya_callbacks.go create mode 100644 pkg/indicator/vidya_test.go create mode 100644 pkg/indicator/volatility.go create mode 100644 pkg/indicator/volatility_callbacks.go create mode 100644 pkg/indicator/volumeprofile.go create mode 100644 pkg/indicator/volumeprofile_test.go create mode 100644 pkg/indicator/vwap.go create mode 100644 pkg/indicator/vwap_callbacks.go create mode 100644 pkg/indicator/vwap_test.go create mode 100644 pkg/indicator/vwma.go create mode 100644 pkg/indicator/vwma_callbacks.go create mode 100644 pkg/indicator/wdrift.go create mode 100644 pkg/indicator/wdrift_test.go create mode 100644 pkg/indicator/weighteddrift_callbacks.go create mode 100644 pkg/indicator/wwma.go create mode 100644 pkg/indicator/wwma_callbacks.go create mode 100644 pkg/indicator/zlema.go create mode 100644 pkg/indicator/zlema_callbacks.go create mode 100644 pkg/indicator/zlema_test.go create mode 100644 pkg/interact/auth.go create mode 100644 pkg/interact/command.go create mode 100644 pkg/interact/default.go create mode 100644 pkg/interact/interact.go create mode 100644 pkg/interact/interact_test.go create mode 100644 pkg/interact/parse.go create mode 100644 pkg/interact/reply.go create mode 100644 pkg/interact/responder.go create mode 100644 pkg/interact/session.go create mode 100644 pkg/interact/slack.go create mode 100644 pkg/interact/slack_callbacks.go create mode 100644 pkg/interact/state.go create mode 100644 pkg/interact/telegram.go create mode 100644 pkg/interact/telegram_callbacks.go create mode 100644 pkg/migrations/mysql/main_20200721225616_trades.go create mode 100644 pkg/migrations/mysql/main_20200819054742_trade_index.go create mode 100644 pkg/migrations/mysql/main_20201102222546_orders.go create mode 100644 pkg/migrations/mysql/main_20201103173342_trades_add_order_id.go create mode 100644 pkg/migrations/mysql/main_20201105092857_trades_index_fix.go create mode 100644 pkg/migrations/mysql/main_20201105093056_orders_add_index.go create mode 100644 pkg/migrations/mysql/main_20201106114742_klines.go create mode 100644 pkg/migrations/mysql/main_20201211175751_fix_symbol_length.go create mode 100644 pkg/migrations/mysql/main_20210118163847_fix_unique_index.go create mode 100644 pkg/migrations/mysql/main_20210119232826_add_margin_columns.go create mode 100644 pkg/migrations/mysql/main_20210129182704_trade_price_quantity_index.go create mode 100644 pkg/migrations/mysql/main_20210215203116_add_pnl_column.go create mode 100644 pkg/migrations/mysql/main_20210223080622_add_rewards_table.go create mode 100644 pkg/migrations/mysql/main_20210301140656_add_withdraws_table.go create mode 100644 pkg/migrations/mysql/main_20210307201830_add_deposits_table.go create mode 100644 pkg/migrations/mysql/main_20210416230730_klines_symbol_length.go create mode 100644 pkg/migrations/mysql/main_20210421091430_increase_symbol_length.go create mode 100644 pkg/migrations/mysql/main_20210421095030_increase_decimal_length.go create mode 100644 pkg/migrations/mysql/main_20210531234123_add_kline_taker_buy_columns.go create mode 100644 pkg/migrations/mysql/main_20211205162043_add_is_futures_column.go create mode 100644 pkg/migrations/mysql/main_20211211020303_add_ftx_kline.go create mode 100644 pkg/migrations/mysql/main_20211211034819_add_nav_history_details.go create mode 100644 pkg/migrations/mysql/main_20211211103657_update_fee_currency_length.go create mode 100644 pkg/migrations/mysql/main_20211226022411_add_kucoin_klines.go create mode 100644 pkg/migrations/mysql/main_20220304153317_add_profit_table.go create mode 100644 pkg/migrations/mysql/main_20220307132917_add_positions.go create mode 100644 pkg/migrations/mysql/main_20220317125555_fix_trade_indexes.go create mode 100644 pkg/migrations/mysql/main_20220419121046_fix_fee_column.go create mode 100644 pkg/migrations/mysql/main_20220503144849_add_margin_info_to_nav.go create mode 100644 pkg/migrations/mysql/main_20220504184155_fix_net_asset_column.go create mode 100644 pkg/migrations/mysql/main_20220512170322_fix_profit_symbol_length.go create mode 100644 pkg/migrations/mysql/main_20220520140707_kline_unique_idx.go create mode 100644 pkg/migrations/mysql/main_20220531012226_margin_loans.go create mode 100644 pkg/migrations/mysql/main_20220531013327_margin_repays.go create mode 100644 pkg/migrations/mysql/main_20220531013542_margin_interests.go create mode 100644 pkg/migrations/mysql/main_20220531015005_margin_liquidations.go create mode 100644 pkg/migrations/mysql/main_20230815173104_add_bybit_klines.go create mode 100644 pkg/migrations/mysql/main_20231123125402_fix_order_status_length.go create mode 100644 pkg/migrations/mysql/main_20240531163411_trades_created.go create mode 100644 pkg/migrations/mysql/migration_api.go create mode 100644 pkg/migrations/mysql/migration_api_test.go create mode 100644 pkg/migrations/sqlite3/main_20200721225616_trades.go create mode 100644 pkg/migrations/sqlite3/main_20200819054742_trade_index.go create mode 100644 pkg/migrations/sqlite3/main_20201102222546_orders.go create mode 100644 pkg/migrations/sqlite3/main_20201103173342_trades_add_order_id.go create mode 100644 pkg/migrations/sqlite3/main_20201105092857_trades_index_fix.go create mode 100644 pkg/migrations/sqlite3/main_20201105093056_orders_add_index.go create mode 100644 pkg/migrations/sqlite3/main_20201106114742_klines.go create mode 100644 pkg/migrations/sqlite3/main_20210118163847_fix_unique_index.go create mode 100644 pkg/migrations/sqlite3/main_20210119232826_add_margin_columns.go create mode 100644 pkg/migrations/sqlite3/main_20210129182704_trade_price_quantity_index.go create mode 100644 pkg/migrations/sqlite3/main_20210215203111_add_pnl_column.go create mode 100644 pkg/migrations/sqlite3/main_20210223080622_add_rewards_table.go create mode 100644 pkg/migrations/sqlite3/main_20210301140656_add_withdraws_table.go create mode 100644 pkg/migrations/sqlite3/main_20210307201830_add_deposits_table.go create mode 100644 pkg/migrations/sqlite3/main_20210531234123_add_kline_taker_buy_columns.go create mode 100644 pkg/migrations/sqlite3/main_20211205162302_add_is_futures_column.go create mode 100644 pkg/migrations/sqlite3/main_20211211020303_add_ftx_kline.go create mode 100644 pkg/migrations/sqlite3/main_20211211034818_add_nav_history_details.go create mode 100644 pkg/migrations/sqlite3/main_20211211103657_update_fee_currency_length.go create mode 100644 pkg/migrations/sqlite3/main_20211226022411_add_kucoin_klines.go create mode 100644 pkg/migrations/sqlite3/main_20220304153309_add_profit_table.go create mode 100644 pkg/migrations/sqlite3/main_20220307132917_add_positions.go create mode 100644 pkg/migrations/sqlite3/main_20220317125555_fix_trade_indexes.go create mode 100644 pkg/migrations/sqlite3/main_20220419121046_fix_fee_column.go create mode 100644 pkg/migrations/sqlite3/main_20220503144849_add_margin_info_to_nav.go create mode 100644 pkg/migrations/sqlite3/main_20220504184155_fix_net_asset_column.go create mode 100644 pkg/migrations/sqlite3/main_20220512170330_fix_profit_symbol_length.go create mode 100644 pkg/migrations/sqlite3/main_20220520140707_kline_unique_idx.go create mode 100644 pkg/migrations/sqlite3/main_20220531012226_margin_loans.go create mode 100644 pkg/migrations/sqlite3/main_20220531013327_margin_repays.go create mode 100644 pkg/migrations/sqlite3/main_20220531013541_margin_interests.go create mode 100644 pkg/migrations/sqlite3/main_20220531015005_margin_liquidations.go create mode 100644 pkg/migrations/sqlite3/main_20230815173104_add_bybit_klines.go create mode 100644 pkg/migrations/sqlite3/main_20231123125402_fix_order_status_length.go create mode 100644 pkg/migrations/sqlite3/main_20240531163411_trades_created.go create mode 100644 pkg/migrations/sqlite3/migration_api.go create mode 100644 pkg/migrations/sqlite3/migration_api_test.go create mode 100644 pkg/net/websocketbase/client.go create mode 100644 pkg/net/websocketbase/websocketclientbase_callbacks.go create mode 100644 pkg/notifier/slacknotifier/slack.go create mode 100644 pkg/notifier/telegramnotifier/logrus_look.go create mode 100644 pkg/notifier/telegramnotifier/telegram.go create mode 100644 pkg/optimizer/config.go create mode 100644 pkg/optimizer/format.go create mode 100644 pkg/optimizer/grid.go create mode 100644 pkg/optimizer/hpoptimizer.go create mode 100644 pkg/optimizer/hpoptimizer_test.go create mode 100644 pkg/optimizer/hyperparam.go create mode 100644 pkg/optimizer/local.go create mode 100644 pkg/optimizer/local_test.go create mode 100644 pkg/optimizer/operator.go create mode 100644 pkg/pb/README.md create mode 100644 pkg/pb/bbgo.pb.go create mode 100644 pkg/pb/bbgo.proto create mode 100644 pkg/pb/bbgo_grpc.pb.go create mode 100644 pkg/pricesolver/simple.go create mode 100644 pkg/pricesolver/simple_test.go create mode 100644 pkg/report/profit_report.go create mode 100644 pkg/report/profit_stats_tracker.go create mode 100644 pkg/risk/circuitbreaker/basic.go create mode 100644 pkg/risk/dynamicrisk/dynamic_exposure.go create mode 100644 pkg/risk/dynamicrisk/dynamic_quantity.go create mode 100644 pkg/risk/dynamicrisk/dynamic_spread.go create mode 100644 pkg/risk/leverage.go create mode 100644 pkg/risk/leverage_test.go create mode 100644 pkg/risk/riskcontrol/circuit_break.go create mode 100644 pkg/risk/riskcontrol/circuit_break_test.go create mode 100644 pkg/risk/riskcontrol/order_price_risk.go create mode 100644 pkg/risk/riskcontrol/order_price_risk_test.go create mode 100644 pkg/risk/riskcontrol/position.go create mode 100644 pkg/risk/riskcontrol/position_test.go create mode 100644 pkg/risk/riskcontrol/positionriskcontrol_callbacks.go create mode 100644 pkg/server/asset_fs.go create mode 100644 pkg/server/assets_dummy.go create mode 100644 pkg/server/envvars.go create mode 100644 pkg/server/ping.go create mode 100644 pkg/server/routes.go create mode 100644 pkg/server/setup.go create mode 100644 pkg/server/utils.go create mode 100644 pkg/service/account.go create mode 100644 pkg/service/account_test.go create mode 100644 pkg/service/backtest.go create mode 100644 pkg/service/backtest_test.go create mode 100644 pkg/service/database.go create mode 100644 pkg/service/db_test.go create mode 100644 pkg/service/deposit.go create mode 100644 pkg/service/deposit_test.go create mode 100644 pkg/service/errors.go create mode 100644 pkg/service/google/sheets.go create mode 100644 pkg/service/margin.go create mode 100644 pkg/service/margin_test.go create mode 100644 pkg/service/memory.go create mode 100644 pkg/service/memory_test.go create mode 100644 pkg/service/order.go create mode 100644 pkg/service/order_test.go create mode 100644 pkg/service/persistence.go create mode 100644 pkg/service/persistence_facade.go create mode 100644 pkg/service/persistence_json.go create mode 100644 pkg/service/persistence_redis.go create mode 100644 pkg/service/persistence_redis_test.go create mode 100644 pkg/service/position.go create mode 100644 pkg/service/position_test.go create mode 100644 pkg/service/profit.go create mode 100644 pkg/service/profit_test.go create mode 100644 pkg/service/reflect.go create mode 100644 pkg/service/reflect_test.go create mode 100644 pkg/service/reward.go create mode 100644 pkg/service/reward_test.go create mode 100644 pkg/service/sync.go create mode 100644 pkg/service/sync_task.go create mode 100644 pkg/service/totp.go create mode 100644 pkg/service/trade.go create mode 100644 pkg/service/trade_test.go create mode 100644 pkg/service/withdraw.go create mode 100644 pkg/service/withdraw_test.go create mode 100644 pkg/sigchan/sigchan.go create mode 100644 pkg/slack/slacklog/logrus_look.go create mode 100644 pkg/slack/slackstyle/style.go create mode 100644 pkg/strategy/atrpin/strategy.go create mode 100644 pkg/strategy/audacitymaker/orderflow.go create mode 100644 pkg/strategy/audacitymaker/strategy.go create mode 100644 pkg/strategy/autoborrow/strategy.go create mode 100644 pkg/strategy/autobuy/strategy.go create mode 100644 pkg/strategy/bollgrid/strategy.go create mode 100644 pkg/strategy/bollmaker/doc.go create mode 100644 pkg/strategy/bollmaker/dynamic_spread.go create mode 100644 pkg/strategy/bollmaker/strategy.go create mode 100644 pkg/strategy/bollmaker/strategy_test.go create mode 100644 pkg/strategy/bollmaker/trend.go create mode 100644 pkg/strategy/common/callbacks.go create mode 100644 pkg/strategy/common/fee_budget.go create mode 100644 pkg/strategy/common/fee_budget_test.go create mode 100644 pkg/strategy/common/inventory_skew.go create mode 100644 pkg/strategy/common/inventory_skew_test.go create mode 100644 pkg/strategy/common/profit_fixer.go create mode 100644 pkg/strategy/common/strategy.go create mode 100644 pkg/strategy/common/sync.go create mode 100644 pkg/strategy/common/sync_test.go create mode 100644 pkg/strategy/convert/strategy.go create mode 100644 pkg/strategy/dca/strategy.go create mode 100644 pkg/strategy/dca2/collector.go create mode 100644 pkg/strategy/dca2/collector_test.go create mode 100644 pkg/strategy/dca2/debug.go create mode 100644 pkg/strategy/dca2/metrics.go create mode 100644 pkg/strategy/dca2/open_position.go create mode 100644 pkg/strategy/dca2/open_position_test.go create mode 100644 pkg/strategy/dca2/profit_stats.go create mode 100644 pkg/strategy/dca2/recover.go create mode 100644 pkg/strategy/dca2/recover_test.go create mode 100644 pkg/strategy/dca2/state.go create mode 100644 pkg/strategy/dca2/strategy.go create mode 100644 pkg/strategy/dca2/strategy_callbacks.go create mode 100644 pkg/strategy/dca2/sync.go create mode 100644 pkg/strategy/dca2/take_profit.go create mode 100644 pkg/strategy/dca2/take_profit_test.go create mode 100644 pkg/strategy/deposit2transfer/strategy.go create mode 100644 pkg/strategy/drift/draw.go create mode 100644 pkg/strategy/drift/driftma.go create mode 100644 pkg/strategy/drift/output.go create mode 100644 pkg/strategy/drift/stoploss.go create mode 100644 pkg/strategy/drift/stoploss_test.go create mode 100644 pkg/strategy/drift/strategy.go create mode 100644 pkg/strategy/drift/strategy_test.go create mode 100644 pkg/strategy/elliottwave/draw.go create mode 100644 pkg/strategy/elliottwave/ewo.go create mode 100644 pkg/strategy/elliottwave/heikinashi.go create mode 100644 pkg/strategy/elliottwave/output.go create mode 100644 pkg/strategy/elliottwave/strategy.go create mode 100644 pkg/strategy/emacross/strategy.go create mode 100644 pkg/strategy/emastop/strategy.go create mode 100644 pkg/strategy/etf/strategy.go create mode 100644 pkg/strategy/ewoDgtrd/heikinashi.go create mode 100644 pkg/strategy/ewoDgtrd/strategy.go create mode 100644 pkg/strategy/factorzoo/factors/mom_callbacks.go create mode 100644 pkg/strategy/factorzoo/factors/momentum.go create mode 100644 pkg/strategy/factorzoo/factors/pmr_callbacks.go create mode 100644 pkg/strategy/factorzoo/factors/price_mean_reversion.go create mode 100644 pkg/strategy/factorzoo/factors/price_volume_divergence.go create mode 100644 pkg/strategy/factorzoo/factors/pvd_callbacks.go create mode 100644 pkg/strategy/factorzoo/factors/return_rate.go create mode 100644 pkg/strategy/factorzoo/factors/rr_callbacks.go create mode 100644 pkg/strategy/factorzoo/factors/vmom_callbacks.go create mode 100644 pkg/strategy/factorzoo/factors/volume_momentum.go create mode 100644 pkg/strategy/factorzoo/linear_regression.go create mode 100644 pkg/strategy/factorzoo/strategy.go create mode 100644 pkg/strategy/fixedmaker/strategy.go create mode 100644 pkg/strategy/flashcrash/strategy.go create mode 100644 pkg/strategy/fmaker/A18.go create mode 100644 pkg/strategy/fmaker/A2.go create mode 100644 pkg/strategy/fmaker/A3.go create mode 100644 pkg/strategy/fmaker/A34.go create mode 100644 pkg/strategy/fmaker/R.go create mode 100644 pkg/strategy/fmaker/S0.go create mode 100644 pkg/strategy/fmaker/S1.go create mode 100644 pkg/strategy/fmaker/S2.go create mode 100644 pkg/strategy/fmaker/S3.go create mode 100644 pkg/strategy/fmaker/S4.go create mode 100644 pkg/strategy/fmaker/S5.go create mode 100644 pkg/strategy/fmaker/S6.go create mode 100644 pkg/strategy/fmaker/S7.go create mode 100644 pkg/strategy/fmaker/a18_callbacks.go create mode 100644 pkg/strategy/fmaker/a2_callbacks.go create mode 100644 pkg/strategy/fmaker/a34_callbacks.go create mode 100644 pkg/strategy/fmaker/a3_callbacks.go create mode 100644 pkg/strategy/fmaker/r_callbacks.go create mode 100644 pkg/strategy/fmaker/s0_callbacks.go create mode 100644 pkg/strategy/fmaker/s1_callbacks.go create mode 100644 pkg/strategy/fmaker/s2_callbacks.go create mode 100644 pkg/strategy/fmaker/s3_callbacks.go create mode 100644 pkg/strategy/fmaker/s4_callbacks.go create mode 100644 pkg/strategy/fmaker/s5_callbacks.go create mode 100644 pkg/strategy/fmaker/s6_callbacks.go create mode 100644 pkg/strategy/fmaker/s7_callbacks.go create mode 100644 pkg/strategy/fmaker/strategy.go create mode 100644 pkg/strategy/grid/strategy.go create mode 100644 pkg/strategy/grid2/backtest_test.go create mode 100644 pkg/strategy/grid2/debug.go create mode 100644 pkg/strategy/grid2/grid.go create mode 100644 pkg/strategy/grid2/grid_dnum_test.go create mode 100644 pkg/strategy/grid2/grid_int64_test.go create mode 100644 pkg/strategy/grid2/grid_recover.go create mode 100644 pkg/strategy/grid2/grid_recover_test.go create mode 100644 pkg/strategy/grid2/grid_test.go create mode 100644 pkg/strategy/grid2/metrics.go create mode 100644 pkg/strategy/grid2/mocks/order_executor.go create mode 100644 pkg/strategy/grid2/pin_order_map.go create mode 100644 pkg/strategy/grid2/pricemap.go create mode 100644 pkg/strategy/grid2/profit.go create mode 100644 pkg/strategy/grid2/profit_fixer.go create mode 100644 pkg/strategy/grid2/profit_fixer_test.go create mode 100644 pkg/strategy/grid2/profit_stats.go create mode 100644 pkg/strategy/grid2/recover.go create mode 100644 pkg/strategy/grid2/recover_test.go create mode 100644 pkg/strategy/grid2/recovery_testcase/testcase1/closed_orders.csv create mode 100644 pkg/strategy/grid2/recovery_testcase/testcase1/open_orders.csv create mode 100644 pkg/strategy/grid2/recovery_testcase/testcase1/spec create mode 100644 pkg/strategy/grid2/recovery_testcase/testcase1/trades.csv create mode 100644 pkg/strategy/grid2/strategy.go create mode 100644 pkg/strategy/grid2/strategy_callbacks.go create mode 100644 pkg/strategy/grid2/strategy_test.go create mode 100644 pkg/strategy/grid2/twin_order.go create mode 100644 pkg/strategy/grid2/twin_order_test.go create mode 100644 pkg/strategy/harmonic/draw.go create mode 100644 pkg/strategy/harmonic/shark.go create mode 100644 pkg/strategy/harmonic/shark_callbacks.go create mode 100644 pkg/strategy/harmonic/strategy.go create mode 100644 pkg/strategy/irr/draw.go create mode 100644 pkg/strategy/irr/neg_return_rate.go create mode 100644 pkg/strategy/irr/nrr_callbacks.go create mode 100644 pkg/strategy/irr/strategy.go create mode 100644 pkg/strategy/kline/strategy.go create mode 100644 pkg/strategy/linregmaker/doc.go create mode 100644 pkg/strategy/linregmaker/strategy.go create mode 100644 pkg/strategy/liquiditymaker/generator.go create mode 100644 pkg/strategy/liquiditymaker/generator_test.go create mode 100644 pkg/strategy/liquiditymaker/strategy.go create mode 100644 pkg/strategy/marketcap/strategy.go create mode 100644 pkg/strategy/pivotshort/breaklow.go create mode 100644 pkg/strategy/pivotshort/failedbreakhigh.go create mode 100644 pkg/strategy/pivotshort/resistance.go create mode 100644 pkg/strategy/pivotshort/resistance_test.go create mode 100644 pkg/strategy/pivotshort/strategy.go create mode 100644 pkg/strategy/pricealert/strategy.go create mode 100644 pkg/strategy/pricedrop/strategy.go create mode 100644 pkg/strategy/random/strategy.go create mode 100644 pkg/strategy/rebalance/multi_market_strategy.go create mode 100644 pkg/strategy/rebalance/order_executor_map.go create mode 100644 pkg/strategy/rebalance/strategy.go create mode 100644 pkg/strategy/rsicross/strategy.go create mode 100644 pkg/strategy/rsmaker/strategy.go create mode 100644 pkg/strategy/schedule/strategy.go create mode 100644 pkg/strategy/scmaker/intensity.go create mode 100644 pkg/strategy/scmaker/strategy.go create mode 100644 pkg/strategy/skeleton/strategy.go create mode 100644 pkg/strategy/supertrend/double_dema.go create mode 100644 pkg/strategy/supertrend/draw.go create mode 100644 pkg/strategy/supertrend/linreg.go create mode 100644 pkg/strategy/supertrend/strategy.go create mode 100644 pkg/strategy/support/strategy.go create mode 100644 pkg/strategy/swing/strategy.go create mode 100644 pkg/strategy/techsignal/strategy.go create mode 100644 pkg/strategy/trendtrader/strategy.go create mode 100644 pkg/strategy/trendtrader/trend.go create mode 100644 pkg/strategy/tri/debug.go create mode 100644 pkg/strategy/tri/debug_null.go create mode 100644 pkg/strategy/tri/market.go create mode 100644 pkg/strategy/tri/path.go create mode 100644 pkg/strategy/tri/position.go create mode 100644 pkg/strategy/tri/profit.go create mode 100644 pkg/strategy/tri/strategy.go create mode 100644 pkg/strategy/tri/strategy_test.go create mode 100644 pkg/strategy/tri/symbols.go create mode 100644 pkg/strategy/tri/symbols.sh create mode 100644 pkg/strategy/tri/utils.go create mode 100644 pkg/strategy/wall/strategy.go create mode 100644 pkg/strategy/xalign/strategy.go create mode 100644 pkg/strategy/xalign/strategy_test.go create mode 100644 pkg/strategy/xbalance/strategy.go create mode 100644 pkg/strategy/xbalance/strategy_test.go create mode 100644 pkg/strategy/xdepthmaker/profitfixer.go create mode 100644 pkg/strategy/xdepthmaker/state.go create mode 100644 pkg/strategy/xdepthmaker/strategy.go create mode 100644 pkg/strategy/xdepthmaker/strategy_test.go create mode 100644 pkg/strategy/xfixedmaker/strategy.go create mode 100644 pkg/strategy/xfunding/fundingfee.go create mode 100644 pkg/strategy/xfunding/positionstate_string.go create mode 100644 pkg/strategy/xfunding/profitstats.go create mode 100644 pkg/strategy/xfunding/strategy.go create mode 100644 pkg/strategy/xfunding/transfer.go create mode 100644 pkg/strategy/xgap/strategy.go create mode 100644 pkg/strategy/xmaker/metrics.go create mode 100644 pkg/strategy/xmaker/signal_boll.go create mode 100644 pkg/strategy/xmaker/signal_book.go create mode 100644 pkg/strategy/xmaker/state.go create mode 100644 pkg/strategy/xmaker/strategy.go create mode 100644 pkg/strategy/xmaker/strategy_test.go create mode 100644 pkg/strategy/xnav/csv.go create mode 100644 pkg/strategy/xnav/strategy.go create mode 100644 pkg/style/colors.go create mode 100644 pkg/style/pnl.go create mode 100644 pkg/style/table.go create mode 100644 pkg/testing/httptesting/client.go create mode 100644 pkg/testing/httptesting/response.go create mode 100644 pkg/testing/httptesting/transport.go create mode 100644 pkg/testing/testhelper/assert_priceside.go create mode 100644 pkg/testing/testhelper/number.go create mode 100644 pkg/testutil/auth.go create mode 100644 pkg/twap/stream_executor.go create mode 100644 pkg/twap/v2/bbomonitor.go create mode 100644 pkg/twap/v2/bbomonitor_callbacks.go create mode 100644 pkg/twap/v2/done.go create mode 100644 pkg/twap/v2/stream_executor.go create mode 100644 pkg/twap/v2/stream_executor_test.go create mode 100644 pkg/types/account.go create mode 100644 pkg/types/account_test.go create mode 100644 pkg/types/asset.go create mode 100644 pkg/types/backtest_stream.go create mode 100644 pkg/types/balance.go create mode 100644 pkg/types/balance_test.go create mode 100644 pkg/types/balance_type.go create mode 100644 pkg/types/bollinger.go create mode 100644 pkg/types/bookticker.go create mode 100644 pkg/types/channel.go create mode 100644 pkg/types/cross.go create mode 100644 pkg/types/csv.go create mode 100644 pkg/types/currencies.go create mode 100644 pkg/types/deposit.go create mode 100644 pkg/types/duration.go create mode 100644 pkg/types/duration_test.go create mode 100644 pkg/types/error.go create mode 100644 pkg/types/exchange.go create mode 100644 pkg/types/exchange_icon.go create mode 100644 pkg/types/exchange_test.go create mode 100644 pkg/types/filter.go create mode 100644 pkg/types/float64updater.go create mode 100644 pkg/types/float64updater_callbacks.go create mode 100644 pkg/types/float_map.go create mode 100644 pkg/types/fundingrate.go create mode 100644 pkg/types/futures.go create mode 100644 pkg/types/heikinashi_stream.go create mode 100644 pkg/types/indicator.go create mode 100644 pkg/types/indicator_test.go create mode 100644 pkg/types/instance.go create mode 100644 pkg/types/interval.go create mode 100644 pkg/types/interval_test.go create mode 100644 pkg/types/json.go create mode 100644 pkg/types/kline.go create mode 100644 pkg/types/kline_test.go create mode 100644 pkg/types/liquidation_info.go create mode 100644 pkg/types/margin.go create mode 100644 pkg/types/market.go create mode 100644 pkg/types/market_test.go create mode 100644 pkg/types/mocks/mock_exchange.go create mode 100644 pkg/types/mocks/mock_exchange_order_query.go create mode 100644 pkg/types/mocks/mock_exchange_public.go create mode 100644 pkg/types/mocks/mock_exchange_trade_history.go create mode 100644 pkg/types/mocks/mock_stream.go create mode 100644 pkg/types/omega.go create mode 100644 pkg/types/omega_test.go create mode 100644 pkg/types/order.go create mode 100644 pkg/types/orderbook.go create mode 100644 pkg/types/orderbook_test.go create mode 100644 pkg/types/ordermap.go create mode 100644 pkg/types/pca.go create mode 100644 pkg/types/persistence_ttl.go create mode 100644 pkg/types/plaintext.go create mode 100644 pkg/types/position.go create mode 100644 pkg/types/positionSide.go create mode 100644 pkg/types/position_metrics.go create mode 100644 pkg/types/position_test.go create mode 100644 pkg/types/premiumindex.go create mode 100644 pkg/types/price_type.go create mode 100644 pkg/types/price_volume_heartbeat.go create mode 100644 pkg/types/price_volume_heartbeat_test.go create mode 100644 pkg/types/price_volume_slice.go create mode 100644 pkg/types/price_volume_slice_test.go create mode 100644 pkg/types/profit.go create mode 100644 pkg/types/queue.go create mode 100644 pkg/types/rbtorderbook.go create mode 100644 pkg/types/rbtorderbook_callbacks.go create mode 100644 pkg/types/rbtorderbook_test.go create mode 100644 pkg/types/rbtree.go create mode 100644 pkg/types/rbtree_node.go create mode 100644 pkg/types/rbtree_test.go create mode 100644 pkg/types/reward.go create mode 100644 pkg/types/series.go create mode 100644 pkg/types/series_float64.go create mode 100644 pkg/types/series_float64_test.go create mode 100644 pkg/types/seriesbase_imp.go create mode 100644 pkg/types/sharpe.go create mode 100644 pkg/types/sharpe_test.go create mode 100644 pkg/types/side.go create mode 100644 pkg/types/sigmoid.go create mode 100644 pkg/types/slack.go create mode 100644 pkg/types/sliceorderbook.go create mode 100644 pkg/types/sliceorderbook_callbacks.go create mode 100644 pkg/types/sliceorderbook_test.go create mode 100644 pkg/types/sort.go create mode 100644 pkg/types/sort_test.go create mode 100644 pkg/types/sortino.go create mode 100644 pkg/types/sortino_test.go create mode 100644 pkg/types/standardstream_callbacks.go create mode 100644 pkg/types/strategy_status.go create mode 100644 pkg/types/stream.go create mode 100644 pkg/types/streamorderbook_callbacks.go create mode 100644 pkg/types/strint.go create mode 100644 pkg/types/syncgroup.go create mode 100644 pkg/types/syncgroup_test.go create mode 100644 pkg/types/ticker.go create mode 100644 pkg/types/time.go create mode 100644 pkg/types/time_test.go create mode 100644 pkg/types/trade.go create mode 100644 pkg/types/trade_stats.go create mode 100644 pkg/types/trade_stats_test.go create mode 100644 pkg/types/trade_test.go create mode 100644 pkg/types/transfer.go create mode 100644 pkg/types/value_map.go create mode 100644 pkg/types/value_map_test.go create mode 100644 pkg/types/withdraw.go create mode 100644 pkg/util/backoff/general.go create mode 100644 pkg/util/dir.go create mode 100644 pkg/util/envvars.go create mode 100644 pkg/util/fnv.go create mode 100644 pkg/util/http_response.go create mode 100644 pkg/util/http_response_test.go create mode 100644 pkg/util/json.go create mode 100644 pkg/util/logerr.go create mode 100644 pkg/util/math_test.go create mode 100644 pkg/util/paper_trade.go create mode 100644 pkg/util/pointer.go create mode 100644 pkg/util/pointer_18.go create mode 100644 pkg/util/profile.go create mode 100644 pkg/util/rate_limit.go create mode 100644 pkg/util/rate_limit_test.go create mode 100644 pkg/util/reonce.go create mode 100644 pkg/util/reonce_test.go create mode 100644 pkg/util/simple_args.go create mode 100644 pkg/util/string.go create mode 100644 pkg/util/string_test.go create mode 100644 pkg/util/templateutil/render.go create mode 100644 pkg/util/time.go create mode 100644 pkg/util/tradingutil/cancel.go create mode 100644 pkg/util/tradingutil/trades.go create mode 100644 pkg/util/tradingutil/trades_test.go create mode 100644 pkg/util/trylock.go create mode 100644 pkg/util/trylock_18.go create mode 100644 pkg/util/volatile_memory.go create mode 100644 pkg/version/dev.go create mode 100644 pkg/version/version.go create mode 100644 rockhopper_mysql.yaml create mode 100644 rockhopper_sqlite.yaml create mode 100644 scripts/bump-minor.sh create mode 100644 scripts/bump-patch.sh create mode 100644 scripts/download-dnum.sh create mode 100644 scripts/download.sh create mode 100644 scripts/goose create mode 100644 scripts/max.sh create mode 100644 scripts/maxapi.sh create mode 100644 scripts/release-test.sh create mode 100644 scripts/setup-bollgrid-dnum.sh create mode 100644 scripts/setup-bollgrid.sh create mode 100644 scripts/setup-bollmaker.sh create mode 100644 scripts/setup-dnum.sh create mode 100644 scripts/setup-grid-dnum.sh create mode 100644 scripts/setup-grid.sh create mode 100644 scripts/setup.sh create mode 100644 scripts/sync_time.sh create mode 100644 scripts/test-mysql-migrations.sh create mode 100644 scripts/test-sqlite3-migrations.sh create mode 100644 testdata/binance-markets.json create mode 100644 utils/changelog.sh create mode 100644 utils/embed/main.go create mode 100644 utils/generate-new-migration.sh create mode 100644 utils/generate-version-file.sh create mode 100644 utils/google-spreadsheet/main.go diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6dfdf4f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +/contracts +.env.* +/linode +/frontend +/desktop +/data +/output diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..b6552d4 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,13 @@ +SLACK_TOKEN=YOUR_TOKEN +SLACK_CHANNEL=CHANNEL_NAME + +# DB_DRIVER="sqlite3" +# DB_DSN="bbgo.sqlite3" +DB_DRIVER=mysql +DB_DSN=root@tcp(127.0.0.1:3306)/bbgo + +MAX_API_KEY=YOUR_API_KEY +MAX_API_SECRET=YOUR_API_SECRET + +BINANCE_API_KEY=YOUR_API_KEY +BINANCE_API_SECRET=YOUR_API_SECRET diff --git a/.evans.toml b/.evans.toml new file mode 100644 index 0000000..e60d2b7 --- /dev/null +++ b/.evans.toml @@ -0,0 +1,3 @@ +[default] +protoFile = ["pkg/pb/bbgo.proto"] +package = "bbgo" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f41e4ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# Created by .ignore support plugin (hsz.mobi) +### Go template +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +.idea + +# Dependency directories (remove the comment below to include it) +# vendor/ +/.mod +/_mod + +/.env.local +/.env.*.local +/.env.production + +.DS_Store + +/build +/dist +/bbgow* + +/config/bbgo.yaml + +/localconfig + +/pkg/server/assets.go + +*.sqlite3 +node_modules +output + +otp*png + +/.deploy + +testoutput + +*.swp +/pkg/backtest/assets.go + +coverage.txt +coverage_dum.txt + +*.cpuprofile + +.systemd.* + +/coverage.txt + +/otp.png + +/profile*.png + +*_local.yaml +/.chglog/ + +/.credentials diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..aba75da --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,9 @@ +run: + issues-exit-code: 0 + tests: true + timeout: 5m +linters: + disable-all: true + enable: + - gofmt + - gosimple diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..cd599ae --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,5 @@ +default: true +extends: null +MD033: false +MD010: false +MD013: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..cbb0418 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,14 @@ +--- +repos: + # Secret Detection + - repo: https://github.com/Yelp/detect-secrets + rev: v1.2.0 + hooks: + - id: detect-secrets + args: ['--exclude-secrets', '3899a918953e01bfe218116cdfeccbed579e26275c4a89abcbc70d2cb9e9bbb8'] + exclude: pacakge.lock.json + # Markdown + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.31.1 + hooks: + - id: markdownlint diff --git a/CLA.md b/CLA.md new file mode 100644 index 0000000..a308bbb --- /dev/null +++ b/CLA.md @@ -0,0 +1,29 @@ +# BBGO Individual Contributor License Agreement + +### *Adapted from http://www.apache.org/licenses/ © Apache Software Foundation.* + +In order to clarify the intellectual property license granted with Contributions from any person or entity, BBGO must have a Contributor License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms below. This CLA is for your protection as a Contributor as well as the protection of BBGO and its users; it does not change your rights to use your own Contributions for any other purpose. + +Please read this document carefully before signing and keep a copy for your records. + +You accept and agree to the following terms and conditions for your present and future Contributions Submitted to BBGO. In return, BBGO shall not use your Contributions in a way that is contrary to the public benefit or inconsistent with its nonprofit status and bylaws in effect at the time of the Contribution. Except for the license granted herein to BBGO and recipients of software distributed by BBGO, You reserve all right, title, and interest in and to your Contributions. + +1. Definitions. "You" (or "Contributor") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this CLA with BBGO. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. + + For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally Submitted by You to BBGO for inclusion in, or documentation of, any of the products owned or managed by BBGO (the "Work"). For the purposes of this definition, "Submitted" means any form of electronic, verbal, or written communication sent to BBGO or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, BBGO for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." + +2. Grant of Copyright License. Subject to the terms and conditions of this CLA, You hereby grant to BBGO and to recipients of software distributed by BBGO a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute your Contributions and such derivative works. + +3. Grant of Patent License. Subject to the terms and conditions of this CLA, You hereby grant to BBGO and to recipients of software distributed by BBGO a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by your Contribution(s) alone or by combination of your Contribution(s) with the Work to which such Contribution(s) was Submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this CLA for that Contribution or Work shall terminate as of the date such litigation is filed. + +4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to BBGO, or that your employer has executed a separate Corporate CLA with BBGO. + +5. You represent that each of your Contributions is your original creation (see section 7 for submissions on behalf of others). You represent that your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of your Contributions. + +6. You are not expected to provide support for your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. You commit not to copy code from another project which license does not allow the duplication / reuse / modification of their source code and / or license is not compatible with the project you are contributing to. As a reminder, a project without an explicit license must be considered as a project with a copyrighted license. + +8. You agree to notify BBGO of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..88a9815 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +pkg/strategy/grid2 @kbearXD @gx578007 +python @narumiruna diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e5e203c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,127 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to participate in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community includes: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct that could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders 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, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +yoanlin93@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: This violation occurs through a single incident or a series of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f25a27d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,80 @@ +# Contributing + +Thank you for investing your time in contributing to our project! :sparkles:. + +Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable. + +In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR. + +## Getting started + +### Issues + +#### Create a new issue + +If you spot a problem, search if an issue already exists. If a related issue doesn't exist, you can open a new issue using a relevant issue form. + +#### Solve an issue + +Scan through our [existing issues](https://github.com/c9s/bbgo/issues) to find one that interests you. +You can narrow down the search using `labels` as filters. As a general rule, we don’t assign issues to anyone. +If you find an issue to work on, you are welcome to open a PR with a fix. + +### Making Changes + +Install pre-commit to check your changes before you commit: + + pip install pre-commit + pre-commit install + pre-commit run markdownlint --files=README.md --verbose + pre-commit run detect-secrets --all-files --verbose + +See for more details. + +For new large features, such as integrating Binance futures contracts, please propose a discussion first before you start working on it. + +For new small features, you could open a pull request directly. + +For each contributor, you have chance to receive the BBG token through the polygon network. + +Each issue has its BBG label, by completing the issue with a pull request, you can get corresponding amount of BBG. + +## Support + +### By contributing pull requests + +Any pull request is welcome, documentation, format fixing, testing, and features. + +### By registering account with referral ID + +You may register your exchange account with my referral ID to support this project. + +- For MAX Exchange: (default commission rate to your account) +- For Binance Exchange: (5% commission back to your account) + +### By small amount of cryptos + +- BTC address `3J6XQJNWT56amqz9Hz2BEVQ7W4aNmb5kiU` +- USDT ERC20 address `0xeBcf7887A5b767DEb2e0C77E46A22c6Adc64E427` +- USDT POLYGON address `0xeBcf7887A5b767DEb2e0C77E46A22c6Adc64E427` + +### Buying BBG token + +BBGO issued a token BBG for the ecosystem (contract +address: on ethereum). + +If you have feature request, you can offer your BBG for contributors. + +BBG/ETH liquidity pool on Uniswap: + +BBG/MATIC pool on quickswap: https://quickswap.exchange/#/swap?outputCurrency=0x3Afe98235d680e8d7A52e1458a59D60f45F935C0 + +For further request, please contact us: + +## Community + +You can join our telegram channels: + +- BBGO International +- BBGO Taiwan + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3be7912 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# First stage container +FROM golang:1.21-alpine3.18 AS builder +RUN apk add --no-cache git ca-certificates gcc musl-dev libc-dev pkgconfig +# gcc is for github.com/mattn/go-sqlite3 +# ADD . $GOPATH/src/github.com/c9s/bbgo + + +WORKDIR $GOPATH/src/github.com/c9s/bbgo +ARG GO_MOD_CACHE +ENV WORKDIR=$GOPATH/src/github.com/c9s/bbgo +ENV GOPATH_ORIG=$GOPATH +ENV GOPATH=${GO_MOD_CACHE:+$WORKDIR/$GO_MOD_CACHE} +ENV GOPATH=${GOPATH:-$GOPATH_ORIG} +ENV CGO_ENABLED=1 +RUN cd $WORKDIR +ADD . . +RUN go get github.com/mattn/go-sqlite3 +RUN go build -o $GOPATH_ORIG/bin/bbgo ./cmd/bbgo + +# Second stage container +FROM alpine:3.18 + +# Create the default user 'bbgo' and assign to env 'USER' +ENV USER=bbgo +RUN adduser -D -G wheel "$USER" +USER ${USER} + +COPY --from=builder /go/bin/bbgo /usr/local/bin + +WORKDIR /home/${USER} +ENTRYPOINT ["/usr/local/bin/bbgo"] +CMD ["run", "--config", "/config/bbgo.yaml", "--no-compile"] +# vim:filetype=dockerfile: diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bdd1b9e --- /dev/null +++ b/Makefile @@ -0,0 +1,277 @@ +TARGET_ARCH ?= amd64 +BUILD_DIR ?= build +BIN_DIR := $(BUILD_DIR)/bbgo +DIST_DIR ?= dist +GIT_DESC := $(shell git describe --tags) + +VERSION ?= $(shell git describe --tags) + +OSX_APP_NAME = BBGO.app +OSX_APP_DIR = build/$(OSX_APP_NAME) +OSX_APP_CONTENTS_DIR = $(OSX_APP_DIR)/Contents +OSX_APP_RESOURCES_DIR = $(OSX_APP_CONTENTS_DIR)/Resources +OSX_APP_CODESIGN_IDENTITY ?= + +# OSX_APP_GUI ?= lorca +OSX_APP_GUI ?= webview + +FRONTEND_EXPORT_DIR = apps/frontend/out + +BACKTEST_REPORT_APP_DIR = apps/backtest-report +BACKTEST_REPORT_EXPORT_DIR = apps/backtest-report/out + +all: bbgo-linux bbgo-darwin + +$(BIN_DIR): + mkdir -p $@ + + +# build native bbgo +bbgo: static + go build -tags web,release -o $(BIN_DIR)/bbgo ./cmd/bbgo + +# build native bbgo (slim version) +bbgo-slim: + go build -tags release -o $(BIN_DIR)/$@ ./cmd/bbgo + +# build cross-compile linux bbgo +bbgo-linux: bbgo-linux-amd64 bbgo-linux-arm64 + +bbgo-linux-amd64: $(BIN_DIR) pkg/server/assets.go + GOOS=linux GOARCH=amd64 go build -tags web,release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-linux-arm64: $(BIN_DIR) pkg/server/assets.go + GOOS=linux GOARCH=arm64 go build -tags web,release -o $(BIN_DIR)/$@ ./cmd/bbgo + +# build cross-compile linux bbgo (slim version) +bbgo-slim-linux: bbgo-slim-linux-amd64 bbgo-slim-linux-arm64 + +bbgo-slim-linux-amd64: $(BIN_DIR) + GOOS=linux GOARCH=amd64 go build -tags release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-linux-arm64: $(BIN_DIR) + GOOS=linux GOARCH=arm64 go build -tags release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-darwin: bbgo-darwin-arm64 bbgo-darwin-amd64 + +bbgo-darwin-arm64: $(BIN_DIR) pkg/server/assets.go + GOOS=darwin GOARCH=arm64 go build -tags web,release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-darwin-amd64: $(BIN_DIR) pkg/server/assets.go + GOOS=darwin GOARCH=amd64 go build -tags web,release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-darwin-arm64: $(BIN_DIR) + GOOS=darwin GOARCH=arm64 go build -tags release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-darwin-amd64: $(BIN_DIR) + GOOS=darwin GOARCH=amd64 go build -tags release -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-darwin: bbgo-slim-darwin-amd64 bbgo-slim-darwin-arm64 + +# build native bbgo +bbgo-dnum: static + go build -tags web,release,dnum -o $(BIN_DIR)/bbgo ./cmd/bbgo + +# build native bbgo (slim version) +bbgo-slim-dnum: + go build -tags release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +# build cross-compile linux bbgo +bbgo-dnum-linux: bbgo-dnum-linux-amd64 bbgo-dnum-linux-arm64 + +bbgo-dnum-linux-amd64: $(BIN_DIR) pkg/server/assets.go + GOOS=linux GOARCH=amd64 go build -tags web,release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-dnum-linux-arm64: $(BIN_DIR) pkg/server/assets.go + GOOS=linux GOARCH=arm64 go build -tags web,release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +# build cross-compile linux bbgo (slim version) +bbgo-slim-dnum-linux: bbgo-slim-dnum-linux-amd64 bbgo-slim-dnum-linux-arm64 + +bbgo-slim-dnum-linux-amd64: $(BIN_DIR) + GOOS=linux GOARCH=amd64 go build -tags release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-dnum-linux-arm64: $(BIN_DIR) + GOOS=linux GOARCH=arm64 go build -tags release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-dnum-darwin: bbgo-dnum-darwin-arm64 bbgo-dnum-darwin-amd64 + +bbgo-dnum-darwin-arm64: $(BIN_DIR) pkg/server/assets.go + GOOS=darwin GOARCH=arm64 go build -tags web,release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-dnum-darwin-amd64: $(BIN_DIR) pkg/server/assets.go + GOOS=darwin GOARCH=amd64 go build -tags web,release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-dnum-darwin-arm64: $(BIN_DIR) + GOOS=darwin GOARCH=arm64 go build -tags release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-dnum-darwin-amd64: $(BIN_DIR) + GOOS=darwin GOARCH=amd64 go build -tags release,dnum -o $(BIN_DIR)/$@ ./cmd/bbgo + +bbgo-slim-dnum-darwin: bbgo-slim-dnum-darwin-amd64 bbgo-slim-dnum-darwin-arm64 + + + +$(OSX_APP_CONTENTS_DIR): + mkdir -p $@ + +$(OSX_APP_CONTENTS_DIR)/MacOS: $(OSX_APP_CONTENTS_DIR) + mkdir -p $@ + +$(OSX_APP_RESOURCES_DIR): $(OSX_APP_CONTENTS_DIR) + mkdir -p $@ + +$(OSX_APP_RESOURCES_DIR)/icon.icns: $(OSX_APP_RESOURCES_DIR) + cp -v desktop/icons/icon.icns $@ + +$(OSX_APP_CONTENTS_DIR)/Info.plist: $(OSX_APP_CONTENTS_DIR) + bash desktop/build-osx-info-plist.sh > $@ + +$(OSX_APP_CONTENTS_DIR)/MacOS/bbgo-desktop: $(OSX_APP_CONTENTS_DIR)/MacOS .FORCE + go build -tags web -o $@ ./cmd/bbgo-$(OSX_APP_GUI) + +desktop-osx: $(OSX_APP_CONTENTS_DIR)/MacOS/bbgo-desktop $(OSX_APP_CONTENTS_DIR)/Info.plist $(OSX_APP_RESOURCES_DIR)/icon.icns + if [[ -n "$(OSX_APP_CODESIGN_IDENTITY)" ]] ; then codesign --deep --force --verbose --sign "$(OSX_APP_CODESIGN_IDENTITY)" $(OSX_APP_DIR) \ + && codesign --verify -vvvv $(OSX_APP_DIR) ; fi + +desktop: desktop-osx + +$(DIST_DIR)/$(VERSION): + mkdir -p $(DIST_DIR)/$(VERSION) + +$(DIST_DIR)/$(VERSION)/bbgo-slim-$(VERSION)-%.tar.gz: bbgo-slim-% $(DIST_DIR)/$(VERSION) + tar -C $(BIN_DIR) -cvzf $@ $< +ifeq ($(SIGN),1) + gpg --yes --detach-sign --armor $@ +endif + +$(DIST_DIR)/$(VERSION)/bbgo-$(VERSION)-%.tar.gz: bbgo-% $(DIST_DIR)/$(VERSION) + tar -C $(BIN_DIR) -cvzf $@ $< +ifeq ($(SIGN),1) + gpg --yes --detach-sign --armor $@ +endif + +$(DIST_DIR)/$(VERSION)/bbgo-slim-dnum-$(VERSION)-%.tar.gz: bbgo-slim-dnum-% $(DIST_DIR)/$(VERSION) + tar -C $(BIN_DIR) -cvzf $@ $< +ifeq ($(SIGN),1) + gpg --yes --detach-sign --armor $@ +endif + +$(DIST_DIR)/$(VERSION)/bbgo-dnum-$(VERSION)-%.tar.gz: bbgo-dnum-% $(DIST_DIR)/$(VERSION) + tar -C $(BIN_DIR) -cvzf $@ $< +ifeq ($(SIGN),1) + gpg --yes --detach-sign --armor $@ +endif + +dist-bbgo-linux: \ + $(DIST_DIR)/$(VERSION)/bbgo-$(VERSION)-linux-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-$(VERSION)-linux-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-$(VERSION)-linux-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-$(VERSION)-linux-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-dnum-$(VERSION)-linux-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-dnum-$(VERSION)-linux-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-dnum-$(VERSION)-linux-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-dnum-$(VERSION)-linux-amd64.tar.gz + +dist-bbgo-darwin: \ + $(DIST_DIR)/$(VERSION)/bbgo-$(VERSION)-darwin-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-$(VERSION)-darwin-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-$(VERSION)-darwin-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-$(VERSION)-darwin-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-dnum-$(VERSION)-darwin-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-dnum-$(VERSION)-darwin-amd64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-dnum-$(VERSION)-darwin-arm64.tar.gz \ + $(DIST_DIR)/$(VERSION)/bbgo-slim-dnum-$(VERSION)-darwin-amd64.tar.gz + +dist: static dist-bbgo-linux dist-bbgo-darwin desktop + +pkg/version/version.go: .FORCE + BUILD_FLAGS="release" bash utils/generate-version-file.sh > $@ + +pkg/version/dev.go: .FORCE + BUILD_FLAGS="!release" VERSION_SUFFIX="-dev" bash utils/generate-version-file.sh > $@ + gofmt -s -w $@ + +dev-version: pkg/version/dev.go + git add $< + git commit $< -m "update dev build version" + +cmd-doc: .FORCE + go run ./cmd/update-doc + git add -v doc/commands + git commit -m "update command doc files" doc/commands || true + +version: pkg/version/version.go pkg/version/dev.go migrations cmd-doc + git add $< $(word 2,$^) + git commit $< $(word 2,$^) -m "bump version to $(VERSION)" || true + [[ -e doc/release/$(VERSION).md ]] || (echo "file doc/release/$(VERSION).md does not exist" ; exit 1) + git add -v doc/release/$(VERSION).md && git commit doc/release/$(VERSION).md -m "add $(VERSION) release note" || true + git tag -f $(VERSION) + git push origin HEAD + git push -f origin $(VERSION) + +migrations: + rockhopper compile --config rockhopper_mysql.yaml --output pkg/migrations/mysql + rockhopper compile --config rockhopper_sqlite.yaml --output pkg/migrations/sqlite3 + git add -v pkg/migrations && git commit -m "compile and update migration package" pkg/migrations || true + +docker: + GOPATH=$(PWD)/_mod go mod download + docker build --build-arg GO_MOD_CACHE=_mod --tag yoanlin/bbgo . + bash -c "[[ -n $(DOCKER_TAG) ]] && docker tag yoanlin/bbgo yoanlin/bbgo:$(DOCKER_TAG)" + +docker-push: + docker push yoanlin/bbgo + bash -c "[[ -n $(DOCKER_TAG) ]] && docker push yoanlin/bbgo:$(DOCKER_TAG)" + +apps/frontend/node_modules: + cd apps/frontend && yarn install + +apps/frontend/out/index.html: apps/frontend/node_modules + cd apps/frontend && yarn export + +pkg/server/assets.go: apps/frontend/out/index.html + go run ./utils/embed -package server -tag web -output $@ $(FRONTEND_EXPORT_DIR) + +$(BACKTEST_REPORT_APP_DIR)/node_modules: + cd $(BACKTEST_REPORT_APP_DIR) && yarn install + +$(BACKTEST_REPORT_APP_DIR)/out/index.html: .FORCE $(BACKTEST_REPORT_APP_DIR)/node_modules + cd $(BACKTEST_REPORT_APP_DIR) && yarn build && yarn export + +pkg/backtest/assets.go: $(BACKTEST_REPORT_APP_DIR)/out/index.html + go run ./utils/embed -package backtest -tag web -output $@ $(BACKTEST_REPORT_EXPORT_DIR) + +embed: pkg/server/assets.go pkg/backtest/assets.go + +static: apps/frontend/out/index.html pkg/server/assets.go pkg/backtest/assets.go + +PROTOS := \ + $(wildcard pkg/pb/*.proto) + +GRPC_GO_DEPS := $(subst .proto,.pb.go,$(PROTOS)) + +%.pb.go: %.proto .FORCE + protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative --go_out=paths=source_relative:. --proto_path=. $< + +grpc-go: $(GRPC_GO_DEPS) + +grpc: grpc-go grpc-py + +install-grpc-tools: + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 + pip install grpcio-tools + +# https://github.com/protocolbuffers/protobuf/issues/1491#issuecomment-261914766 +# replace `import bbgo_pb2` by `from . import bbgo_pb2` to use relative import +grpc-py: + python -m grpc_tools.protoc -I$(PWD)/pkg/pb \ + --python_out=$(PWD)/python \ + --grpc_python_out=$(PWD)/python \ + $(PWD)/pkg/pb/bbgo.proto + +clean: + rm -rf $(BUILD_DIR) $(DIST_DIR) $(FRONTEND_EXPORT_DIR) $(GRPC_GO_DEPS) pkg/pb/*.pb.go coverage.txt + +.PHONY: bbgo bbgo-slim-darwin bbgo-slim-darwin-amd64 bbgo-slim-darwin-arm64 bbgo-darwin version dist pack migrations static embed desktop grpc grpc-go grpc-py .FORCE diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..95896ea --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +worker: bin/bbgo run --config config/bbgo.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc2bfd8 --- /dev/null +++ b/README.md @@ -0,0 +1,667 @@ +* [English👈](./README.md) +* [中文](./README.zh_TW.md) + +# BBGO + +A modern crypto trading bot framework written in Go. + +## Current Status + +[![Go](https://github.com/c9s/bbgo/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/c9s/bbgo/actions/workflows/go.yml) +[![GoDoc](https://godoc.org/github.com/c9s/bbgo?status.svg)](https://pkg.go.dev/github.com/c9s/bbgo) +[![Go Report Card](https://goreportcard.com/badge/github.com/c9s/bbgo)](https://goreportcard.com/report/github.com/c9s/bbgo) +[![DockerHub](https://img.shields.io/docker/pulls/yoanlin/bbgo.svg)](https://hub.docker.com/r/yoanlin/bbgo) +[![Coverage Status](http://codecov.io/github/c9s/bbgo/coverage.svg?branch=main)](http://codecov.io/github/c9s/bbgo?branch=main) +open collective badge +open collective badge + +## Community + +[![Telegram Global](https://img.shields.io/badge/telegram-global-blue.svg)](https://t.me/bbgo_intl) +[![Telegram Taiwan](https://img.shields.io/badge/telegram-tw-blue.svg)](https://t.me/bbgocrypto) +[![Twitter](https://img.shields.io/twitter/follow/bbgotrading?label=Follow&style=social)](https://twitter.com/bbgotrading) + +## What You Can Do With BBGO + +### Trading Bot Users 💁‍♀️ 💁‍♂️ + +You can use BBGO to run the built-in strategies. + +### Strategy Developers 🥷 + +You can use BBGO's trading unit and back-test unit to implement your own strategies. + +### Trading Unit Developers 🧑‍💻 + +You can use BBGO's underlying common exchange API; currently, it supports 4+ major exchanges, so you don't have to repeat +the implementation. + +## Features + +- Exchange abstraction interface. +- Stream integration (user data web socket, market data web socket). +- Real-time orderBook integration through a web socket. +- TWAP order execution support. See [TWAP Order Execution](./doc/topics/twap.md) +- PnL calculation. +- Slack/Telegram notification. +- Back-testing: KLine-based back-testing engine. See [Back-testing](./doc/topics/back-testing.md) +- Built-in parameter optimization tool. +- Built-in Grid strategy and many other built-in strategies. +- Multi-exchange session support: you can connect to more than 2 exchanges with different accounts or subaccounts. +- Indicators with interface similar + to `pandas.Series`([series](https://github.com/c9s/bbgo/blob/main/doc/development/series.md))([usage](https://github.com/c9s/bbgo/blob/main/doc/development/indicator.md)): + - [Accumulation/Distribution Indicator](./pkg/indicator/ad.go) + - [Arnaud Legoux Moving Average](./pkg/indicator/alma.go) + - [Average True Range](./pkg/indicator/atr.go) + - [Bollinger Bands](./pkg/indicator/boll.go) + - [Commodity Channel Index](./pkg/indicator/cci.go) + - [Cumulative Moving Average](./pkg/indicator/cma.go) + - [Double Exponential Moving Average](./pkg/indicator/dema.go) + - [Directional Movement Index](./pkg/indicator/dmi.go) + - [Brownian Motion's Drift Factor](./pkg/indicator/drift.go) + - [Ease of Movement](./pkg/indicator/emv.go) + - [Exponentially Weighted Moving Average](./pkg/indicator/ewma.go) + - [Hull Moving Average](./pkg/indicator/hull.go) + - [Trend Line (Tool)](./pkg/indicator/line.go) + - [Moving Average Convergence Divergence Indicator](./pkg/indicator/macd.go) + - [On-Balance Volume](./pkg/indicator/obv.go) + - [Pivot](./pkg/indicator/pivot.go) + - [Running Moving Average](./pkg/indicator/rma.go) + - [Relative Strength Index](./pkg/indicator/rsi.go) + - [Simple Moving Average](./pkg/indicator/sma.go) + - [Ehler's Super Smoother Filter](./pkg/indicator/ssf.go) + - [Stochastic Oscillator](./pkg/indicator/stoch.go) + - [SuperTrend](./pkg/indicator/supertrend.go) + - [Triple Exponential Moving Average](./pkg/indicator/tema.go) + - [Tillson T3 Moving Average](./pkg/indicator/till.go) + - [Triangular Moving Average](./pkg/indicator/tma.go) + - [Variable Index Dynamic Average](./pkg/indicator/vidya.go) + - [Volatility Indicator](./pkg/indicator/volatility.go) + - [Volume Weighted Average Price](./pkg/indicator/vwap.go) + - [Zero Lag Exponential Moving Average](./pkg/indicator/zlema.go) + - And more... +- HeikinAshi OHLC / Normal OHLC (check [this config](https://github.com/c9s/bbgo/blob/main/config/skeleton.yaml#L5)) +- React-powered Web Dashboard. +- Docker image ready. +- Kubernetes support. +- Helm chart ready. +- High precision float point (up to 16 digits, run with `-tags dnum`). + +## Screenshots + +![bbgo dashboard](assets/screenshots/dashboard.jpeg) + +![bbgo backtest report](assets/screenshots/backtest-report.jpg) + +## Built-in Strategies + +| strategy | description | type | backtest support | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------|------------------| +| grid | the first generation grid strategy, it provides more flexibility, but you need to prepare inventories | maker | | +| grid2 | the second generation grid strategy, it can convert your quote asset into a grid, supports base+quote mode | maker | | +| bollgrid | strategy implements a basic grid strategy with the built-in bollinger indicator | maker | | +| xmaker | cross exchange market making strategy, it hedges your inventory risk on the other side | maker | no | +| xnav | this strategy helps you record the current net asset value | tool | no | +| xalign | this strategy aligns your balance position automatically | tool | no | +| xfunding | a funding rate fee strategy | funding | no | +| autoborrow | this strategy uses margin to borrow assets, to help you keep a minimal balance | tool | no | +| pivotshort | this strategy finds the pivot low and enters the trade when the price breaks the previous low | long/short | | +| schedule | this strategy buy/sell with a fixed quantity periodically, you can use this as a single DCA, or to refill the fee asset like BNB. | tool | +| irr | this strategy opens the position based on the predicated return rate | long/short | | +| bollmaker | this strategy holds a long-term long/short position, places maker orders on both sides, and uses a bollinger band to control the position size | maker | | +| wall | this strategy creates a wall (large amount of order) on the order book | maker | no | +| scmaker | this market making strategy is designed for stable coin markets, like USDC/USDT | maker | | +| drift | | long/short | | +| rsicross | this strategy opens a long position when the fast rsi crosses over the slow rsi, this is a demo strategy for using the v2 indicator | long/short | | +| marketcap | this strategy implements a strategy that rebalances the portfolio based on the market capitalization | rebalance | no | +| supertrend | this strategy uses DEMA and Supertrend indicator to open the long/short position | long/short | | +| trendtrader | this strategy opens a long/short position based on the trendline breakout | long/short | | +| elliottwave | | long/short | | +| ewoDgtrd | | long/short | | +| fixedmaker | | maker | | +| factoryzoo | | long/short | | +| fmaker | | maker | | +| linregmaker | a linear regression based market maker | maker | | +| convert | convert strategy is a tool that helps you convert a specific asset to a target asset | tool | no | + + + + +## Supported Exchanges + +- Binance Spot Exchange (and binance.us) +- OKEx Spot Exchange +- Kucoin Spot Exchange +- MAX Spot Exchange (located in Taiwan) +- Bitget Exchange +- Bybit Exchange + +## Documentation and General Topics + +- Check the [documentation index](doc/README.md) + +## Requirements + +* Go SDK 1.20 + +* Linux / MacOS / Windows (WSL) + +* Get your exchange API key and secret after you register the accounts (you can choose one or more exchanges): + + - MAX: + - Binance: + - OKEx: + - Kucoin: + + This project is maintained and supported by a small group of people. If you would like to support this project, please + Register on the exchanges using the provided links with the referral codes above. + +## Installation + +### Install from binary + +The following script will help you set up a config file and a dotenv file: + +```sh +# grid trading strategy for binance exchange +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-grid.sh) binance + +# grid trading strategy for max exchange +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-grid.sh) max + +# bollinger grid trading strategy for binance exchange +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-bollgrid.sh) binance + +# bollinger grid trading strategy for max exchange +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-bollgrid.sh) max +``` + +If you already have configuration somewhere, a download-only script might be suitable for you: + +```sh +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/download.sh) +``` + +Or refer to the [Release Page](https://github.com/c9s/bbgo/releases) and download manually. + +Since v2, we've added a new float point implementation from dnum to support decimals with higher precision. To download & +setup, please refer to [Dnum Installation](doc/topics/dnum-binary.md) + +### One-click Linode StackScript + +StackScript allows you to one-click deploy a lightweight instance with bbgo. + +- BBGO grid on Binance +- BBGO grid USDT/TWD on MAX +- BBGO grid USDC/TWD on MAX +- BBGO grid LINK/TWD on MAX +- BBGO grid USDC/USDT on MAX +- BBGO grid on MAX +- BBGO bollmaker on Binance + +### Build from source + +See [Build from source](./doc/build-from-source.md) + +## Configuration + +Add your dotenv file: + +```sh +# for Binance Exchange, if you have one +BINANCE_API_KEY= +BINANCE_API_SECRET= + +# if you want to use binance.us, change this to 1 +BINANCE_US=0 + +# for MAX exchange, if you have one +MAX_API_KEY= +MAX_API_SECRET= + +# for OKEx exchange, if you have one +OKEX_API_KEY= +OKEX_API_SECRET= +OKEX_API_PASSPHRASE + +# for kucoin exchange, if you have one +KUCOIN_API_KEY= +KUCOIN_API_SECRET= +KUCOIN_API_PASSPHRASE= +KUCOIN_API_KEY_VERSION=2 + +# for Bybit exchange, if you have one +BYBIT_API_KEY= +BYBIT_API_SECRET= +``` + +Prepare your dotenv file `.env.local` and BBGO yaml config file `bbgo.yaml`. + +To check the available environment variables, please see [Environment Variables](./doc/configuration/envvars.md) + +The minimal bbgo.yaml could be generated by: + +```sh +curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml +``` + +To run strategy: + +```sh +bbgo run +``` + +To start bbgo with the frontend dashboard: + +```sh +bbgo run --enable-webserver +``` + +If you want to switch to another dotenv file, you can add an `--dotenv` option or `--config`: + +```sh +bbgo sync --dotenv .env.dev --config config/grid.yaml --session binance +``` + +To query transfer history: + +```sh +bbgo transfer-history --session max --asset USDT --since "2019-01-01" +``` + + + +## Advanced Configuration + +### Synchronize System Time With Binance + +BBGO provides the script for UNIX systems/subsystems to synchronize date with Binance. `jq` and `bc` are required to be +installed in previous. +To install the dependencies in Ubuntu, try the following commands: + +```bash +sudo apt install -y bc jq +``` + +And to synchronize the date, try: + +```bash +sudo ./scripts/sync_time.sh +``` + +You could also add the script to crontab so that the system time could get synchronized with Binance regularly. + +### Testnet (Paper Trading) + +Currently only supports Binance testnet. To run bbgo in testnet, apply new API keys +from [Binance Test Network](https://testnet.binance.vision), and set the following env before you start bbgo: + +```bash +export PAPER_TRADE=1 +export DISABLE_MARKET_CACHE=1 # the symbols supported in testnet is far less than the mainnet +``` + +### Notification + +- [Setting up Telegram notification](./doc/configuration/telegram.md) +- [Setting up Slack notification](./doc/configuration/slack.md) + +### Synchronizing Trading Data + +By default, BBGO does not sync your trading data from the exchange sessions, so it's hard to calculate your profit and +loss correctly. + +By synchronizing trades and orders to the local database, you can earn some benefits like PnL calculations, backtesting +and asset calculation. + +You can only use one database driver MySQL or SQLite to store your trading data. + +**Notice**: SQLite is not fully supported, we recommend you use MySQL instead of SQLite. + +#### Configure MySQL Database + +To use MySQL database for data syncing, first, you need to install your MySQL server: + +```sh +# For Ubuntu Linux +sudo apt-get install -y mysql-server + +# For newer Ubuntu Linux +sudo apt install -y mysql-server +``` + +Or [run it in docker](https://hub.docker.com/_/mysql) + +Create your mysql database: + +```sh +mysql -uroot -e "CREATE DATABASE bbgo CHARSET utf8" +``` + +Then put these environment variables in your `.env.local` file: + +```sh +DB_DRIVER=mysql +DB_DSN="user:password@tcp(127.0.0.1:3306)/bbgo" +``` + +#### Configure Sqlite3 Database + +To use SQLite3 instead of MySQL, simply put these environment variables in your `.env.local` file: + +```sh +DB_DRIVER=sqlite3 +DB_DSN=bbgo.sqlite3 +``` + +## Synchronizing your own trading data + +Once you have your database configured, you can sync your own trading data from the exchange. + +See [Configure Sync For Private Trading Data](./doc/configuration/sync.md) + +## Using Redis to keep persistence between BBGO sessions + +To use Redis, first you need to install your Redis server: + +```sh +# For Ubuntu/Debian Linux +sudo apt-get install -y redis + +# For newer Ubuntu/Debian Linux +sudo apt install -y redis +``` + +Set the following environment variables in your `bbgo.yaml`: + +```yaml +persistence: + redis: + host: 127.0.0.1 # The IP address or the hostname to your Redis server, 127.0.0.1 if same as BBGO + port: 6379 # Port to Redis server, default 6379 + db: 0 # DB number to use. You can set to another DB to avoid conflict if other applications are using Redis too. +``` + +## Built-in Strategies + +Check out the strategy directory [strategy](pkg/strategy) for all built-in strategies: + +- `pricealert` strategy demonstrates how to use the notification system [pricealert](pkg/strategy/pricealert). See + [document](./doc/strategy/pricealert.md). +- `buyandhold` strategy demonstrates how to subscribe kline events and submit market + order [buyandhold](pkg/strategy/pricedrop) +- `bollgrid` strategy implements a basic grid strategy with the built-in bollinger + indicator [bollgrid](pkg/strategy/bollgrid) +- `grid` strategy implements the fixed price band grid strategy [grid](pkg/strategy/grid). See + [document](./doc/strategy/grid.md). +- `supertrend` strategy uses Supertrend indicator as trend, and DEMA indicator as noise + filter [supertrend](pkg/strategy/supertrend). See + [document](./doc/strategy/supertrend.md). +- `support` strategy uses K-lines with high volume as support [support](pkg/strategy/support). See + [document](./doc/strategy/support.md). +- `flashcrash` strategy implements a strategy that catches the flashcrash [flashcrash](pkg/strategy/flashcrash) +- `marketcap` strategy implements a strategy that rebalances the portfolio based on the market + capitalization [marketcap](pkg/strategy/marketcap). See [document](./doc/strategy/marketcap.md). +- `pivotshort` - shorting focused strategy. +- `irr` - return rate strategy. +- `drift` - drift strategy. +- `grid2` - the second-generation grid strategy. +- `rebalance` - rebalances your portfolio based on target weights. [rebalance](pkg/strategy/rebalance). See [document](./doc/strategy/rebalance.md). + +To run these built-in strategies, just modify the config file to make the configuration suitable for you, for example, if +you want to run +`buyandhold` strategy: + +```sh +vim config/buyandhold.yaml + +# run bbgo with the config +bbgo run --config config/buyandhold.yaml +``` + +## Back-testing + +See [Back-testing](./doc/topics/back-testing.md) + +## Adding Strategy + +See [Developing Strategy](./doc/topics/developing-strategy.md) + +## Write your own private strategy + +Create your go package, initialize the repository with `go mod`, and add bbgo as a dependency: + +```sh +go mod init +go get github.com/c9s/bbgo@main +``` + +Write your own strategy in the strategy file: + +```sh +vim strategy.go +``` + +You can grab the skeleton strategy from + +Now add your config: + +```sh +mkdir config +(cd config && curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml) +``` + +Add your strategy package path to the config file `config/bbgo.yaml` + +```yaml +--- +build: + dir: build + imports: + - github.com/your_id/your_swing + targets: + - name: swing-amd64-linux + os: linux + arch: amd64 + - name: swing-amd64-darwin + os: darwin + arch: amd64 +``` + +Run `bbgo run` command, bbgo will compile a wrapper binary that imports your strategy: + +```sh +dotenv -f .env.local -- bbgo run --config config/bbgo.yaml +``` + +Or you can build your own wrapper binary via: + +```shell +bbgo build --config config/bbgo.yaml +``` + +See also: + +- +- +- +- +- + +## Command Usages + +### Submitting Orders to a specific exchange session + +```shell +bbgo submit-order --session=okex --symbol=OKBUSDT --side=buy --price=10.0 --quantity=1 +``` + +### Listing Open Orders of a specific exchange session + +```sh +bbgo list-orders open --session=okex --symbol=OKBUSDT +bbgo list-orders open --session=max --symbol=MAXUSDT +bbgo list-orders open --session=binance --symbol=BNBUSDT +``` + +### Canceling an open order + +```shell +# both order id and symbol is required for okex +bbgo cancel-order --session=okex --order-id=318223238325248000 --symbol=OKBUSDT + +# for max, you can just give your order id +bbgo cancel-order --session=max --order-id=1234566 +``` + +### Debugging user data stream + +```shell +bbgo userdatastream --session okex +bbgo userdatastream --session max +bbgo userdatastream --session binance +``` + +## Dynamic Injection + +In order to minimize the strategy code, bbgo supports dynamic dependency injection. + +Before executing your strategy, bbgo injects the components into your strategy object if it finds the embedded field +that is using bbgo component. for example: + +```go +type Strategy struct { + Symbol string `json:"symbol" + Market types.Market +} +``` + +Supported components (single exchange strategy only for now): + +- `*bbgo.ExchangeSession` +- `bbgo.OrderExecutor` + +If you have `Symbol string` field in your strategy, your strategy will be detected as a symbol-based strategy, then the +following types could be injected automatically: + +- `types.Market` + +## Strategy Execution Phases + +1. Load config from the config file. +2. Allocate and initialize exchange sessions. +3. Add exchange sessions to the environment (the data layer). +4. Use the given environment to initialize the trader object (the logic layer). +5. The trader initializes the environment and starts the exchange connections. +6. Call strategy.Run() method sequentially. + +## Exchange API Examples + +Please check out the example directory: [examples](examples) + +Initialize MAX API: + +```go +key := os.Getenv("MAX_API_KEY") +secret := os.Getenv("MAX_API_SECRET") + +maxRest := maxapi.NewRestClient(maxapi.ProductionAPIURL) +maxRest.Auth(key, secret) +``` + +Creating user data stream to get the order book (depth): + +```go +stream := max.NewStream(key, secret) +stream.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{}) + +streambook := types.NewStreamBook(symbol) +streambook.BindStream(stream) +``` + +## Deployment + +- [Helm Chart](./doc/deployment/helm-chart.md) +- Baremetal machine or a VPS + +## Development + +- [Adding New Exchange](./doc/development/adding-new-exchange.md) +- [Migration](./doc/development/migration.md) + +### Setting up your local repository + +1. Click the "Fork" button from the GitHub repository. +2. Clone your forked repository into `$GOPATH/github.com/c9s/bbgo`. +3. Change the directory to `$GOPATH/github.com/c9s/bbgo`. +4. Create a branch and start your development. +5. Test your changes. +6. Push your changes to your fork. +7. Send a pull request. + +### Testing Desktop App + +for webview + +```sh +make embed && go run -tags web ./cmd/bbgo-webview +``` + +for lorca + +```sh +make embed && go run -tags web ./cmd/bbgo-lorca +``` + +## FAQ + +### What's Position? + +- Base Currency & Quote Currency +- How to calculate the average cost? + +### Looking For A New Strategy? + +You can write an article about BBGO on any topic, in 750-1500 words for exchange, and I can implement the strategy for +you (depending on the complexity and effort). If you're interested in, DM me in telegram or +twitter , and we can discuss. + +### Adding New Crypto Exchange support? + +If you want BBGO to support a new crypto exchange that is not included in the current BBGO, we can implement it for you. +The cost is 10 ETH. If you're interested in it, DM me in telegram . + +## Community + +- Telegram Group +- Telegram Group (Taiwan) +- Twitter + +## Contributing + +See [Contributing](./CONTRIBUTING.md) + +### Financial Contributors + +[[Become a backer](https://opencollective.com/bbgo#backer)] + + + +## BBGO Tokenomics + +To support the development of BBGO, we have created a bounty pool to support contributors by giving away $BBG tokens. +Check the details in [$BBG Contract Page](contracts/README.md) and our [official website](https://bbgo.finance) + +## Supporter + +- GitBook + +## License + +AGPL License diff --git a/README.zh_TW.md b/README.zh_TW.md new file mode 100644 index 0000000..c0ae139 --- /dev/null +++ b/README.zh_TW.md @@ -0,0 +1,624 @@ +* [English](./README.md) +* [中文👈](./README.zh_TW.md) + +# BBGO + +一個用Go編寫的現代加密貨幣交易機器人框架。 +A modern crypto trading bot framework written in Go. + + +## 目前狀態 + +[![Go](https://github.com/c9s/bbgo/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/c9s/bbgo/actions/workflows/go.yml) +[![GoDoc](https://godoc.org/github.com/c9s/bbgo?status.svg)](https://pkg.go.dev/github.com/c9s/bbgo) +[![Go Report Card](https://goreportcard.com/badge/github.com/c9s/bbgo)](https://goreportcard.com/report/github.com/c9s/bbgo) +[![DockerHub](https://img.shields.io/docker/pulls/yoanlin/bbgo.svg)](https://hub.docker.com/r/yoanlin/bbgo) +[![Coverage Status](http://codecov.io/github/c9s/bbgo/coverage.svg?branch=main)](http://codecov.io/github/c9s/bbgo?branch=main) +open collective badge +open collective badge + +## 社群 + +[![Telegram Global](https://img.shields.io/badge/telegram-global-blue.svg)](https://t.me/bbgo_intl) +[![Telegram Taiwan](https://img.shields.io/badge/telegram-tw-blue.svg)](https://t.me/bbgocrypto) +[![Twitter](https://img.shields.io/twitter/follow/bbgotrading?label=Follow&style=social)](https://twitter.com/bbgotrading) + +## 你可以用 BBGO 做什麼 +### 交易機器人用戶 💁‍♀️ 💁‍♂️ +您可以使用 BBGO 運行內置策略。 + +### 策略開發者 🥷 +您可以使用 BBGO 的交易單元和回測單元來實現您自己的策略。 + +### 交易單元開發者 🧑‍💻 +您可以使用 BBGO 的底層共用交易所 API;目前它支持 4+ 個主要交易所,因此您不必重複實現。 + +## 特色 +* 交易所抽象介面。 +* 整合串流(用戶資料 websocket,市場資料 websocket)。 +* 通過 websocket 實時訂單簿整合。 +* TWAP 訂單執行支持。參見 [TWAP 訂單執行](./doc/topics/twap.md) +* 盈虧計算。 +* Slack / Telegram 通知。 +* 回測:基於K線的回測引擎。參見[回測](./doc/topics/back-testing.md) +* 內置參數優化工具。 +* 內置網格策略和許多其他內置策略。 +* 多交易所 session 支持:您可以連接到2個以上不同帳戶或子帳戶的交易所。 +* 類似於 `pandas.Series` 的指標介面 ([series](https://github.com/c9s/bbgo/blob/main/doc/development/series.md))([usage](https://github.com/c9s/bbgo/blob/main/doc/development/indicator.md)) + - [Accumulation/Distribution Indicator](./pkg/indicator/ad.go) + - [Arnaud Legoux Moving Average](./pkg/indicator/alma.go) + - [Average True Range](./pkg/indicator/atr.go) + - [Bollinger Bands](./pkg/indicator/boll.go) + - [Commodity Channel Index](./pkg/indicator/cci.go) + - [Cumulative Moving Average](./pkg/indicator/cma.go) + - [Double Exponential Moving Average](./pkg/indicator/dema.go) + - [Directional Movement Index](./pkg/indicator/dmi.go) + - [Brownian Motion's Drift Factor](./pkg/indicator/drift.go) + - [Ease of Movement](./pkg/indicator/emv.go) + - [Exponentially Weighted Moving Average](./pkg/indicator/ewma.go) + - [Hull Moving Average](./pkg/indicator/hull.go) + - [Trend Line (Tool)](./pkg/indicator/line.go) + - [Moving Average Convergence Divergence Indicator](./pkg/indicator/macd.go) + - [On-Balance Volume](./pkg/indicator/obv.go) + - [Pivot](./pkg/indicator/pivot.go) + - [Running Moving Average](./pkg/indicator/rma.go) + - [Relative Strength Index](./pkg/indicator/rsi.go) + - [Simple Moving Average](./pkg/indicator/sma.go) + - [Ehler's Super Smoother Filter](./pkg/indicator/ssf.go) + - [Stochastic Oscillator](./pkg/indicator/stoch.go) + - [SuperTrend](./pkg/indicator/supertrend.go) + - [Triple Exponential Moving Average](./pkg/indicator/tema.go) + - [Tillson T3 Moving Average](./pkg/indicator/till.go) + - [Triangular Moving Average](./pkg/indicator/tma.go) + - [Variable Index Dynamic Average](./pkg/indicator/vidya.go) + - [Volatility Indicator](./pkg/indicator/volatility.go) + - [Volume Weighted Average Price](./pkg/indicator/vwap.go) + - [Zero Lag Exponential Moving Average](./pkg/indicator/zlema.go) + - 更多... + +## 截圖 + +![BBGO 儀表板](assets/screenshots/dashboard.jpeg) + +![BBGO 回測報告](assets/screenshots/backtest-report.jpg) + +## 內建策略 + +| 策略 | 描述 | 交易類型 | 是否支援回測 | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------|------------------| +| grid | 第一代網格策略,提供更多的靈活性,但您需要準備庫存。 | maker | | +| grid2 | 第二代網格策略,可以將您的報價資產轉換成網格,支持基礎+報價模式。 | maker | | +| bollgrid | 實現了一個基本的網格策略,內置布林通道 (bollinger band)。 | maker | | +| xmaker | 跨交易所市場製造策略,它在另一邊對您的庫存風險進行對沖。 | maker | 不 | +| xnav | 這個策略幫助您記錄當前的淨資產價值。 | tool | 不 | +| xalign | 這個策略自動對齊您的餘額位置。 | tool | 不 | +| xfunding | 一種資金費率策略。 | funding | 不 | +| autoborrow | 這個策略使用保證金借入資產,幫助您保持最小餘額。 | tool | 不 | +| pivotshort | 這個策略找到支點低點並在價格突破前一低點時進行交易。 | long/short | | +| schedule | 這個策略定期以固定數量買賣,您可以將其用作單一的DCA,或補充像BNB這樣的費用資產。 | tool | +| irr | 這個策略基於預測的回報率開倉。 | long/short | | +| bollmaker | 這個策略持有長期多空倉位,在兩邊下單,並使用布林通道 (bollinger band) 控制倉位大小。| maker | | +| wall | 這個策略在訂單簿上創建一堵牆(大量訂單)。 | maker | 不 | +| scmaker | 這個市場製造策略是為穩定幣市場設計的,如USDC/USDT。 | maker | | +| drift | | long/short | | +| rsicross | 這個策略在快速 RSI 越過慢速 RSI 時開啟多倉,這是使用 v2 指標的演示策略。 | long/short | | +| marketcap | 這個策略實現了一個基於市值資本化重新平衡投資組合的策略。 | rebalance | 不 | +| supertrend | 這個策略使用 DEMA 和超級趨勢指標開啟多空倉位。 | long/short | | +| trendtrader | 這個策略基於趨勢線突破開啟多空倉位。 | long/short | | +| elliottwave | | long/short | | +| ewoDgtrd | | long/short | | +| fixedmaker | | maker | | +| factoryzoo | | long/short | | +| fmaker | | maker | | +| linregmaker | 一個基於線性回歸的市場製造商。 | maker | | +| convert | 轉換策略是一個幫助您將特定資產轉換為目標資產的工具。 | tool | 不 | + +## 已支援交易所 + +- Binance Spot Exchange (以及 binance.us) +- OKEx Spot Exchange +- Kucoin Spot Exchange +- MAX Spot Exchange (台灣交易所) +- Bitget Exchange +- Bybit Exchange + +## 文件 + +- [參考文件](doc/README.md) + +## 要求 + +* Go SDK 1.20 +* Linux / MacOS / Windows (WSL) +* 在您註冊賬戶後獲取您的交易所 API 密鑰和密碼(您可以選擇一個或多個交易所): + - MAX: https://max.maicoin.com/signup?r=c7982718 + - Binance: https://accounts.binance.com/en/register?ref=38192708 + - OKEx: https://www.okex.com/join/2412712?src=from:ios-share + - Kucoin: https://www.kucoin.com/ucenter/signup?rcode=r3KX2D4 + +這個項目由一小群人維護和支持。如果您想支持這個項目,請使用上面提供的鏈接和推薦碼在交易所註冊。 + +## 安裝 + +### 從 binary 安裝 + +以下 script 將幫助你設置文件和 dotenv 文件: + +```sh +# 針對 Binance 交易所的網格交易策略 +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-grid.sh) binance + +# 針對 MAX 交易所的網格交易策略 +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-grid.sh) max + +# 針對 Binance 交易所的布林格網格交易策略 +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-bollgrid.sh) binance + +# 針對 MAX 交易所的布林格網格交易策略 +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/setup-bollgrid.sh) max +``` + +如果您已經在某處有配置,則可能適合您的是僅下載腳本: + +```sh +bash <(curl -s https://raw.githubusercontent.com/c9s/bbgo/main/scripts/download.sh) +``` + +或者參考[發布頁面](https://github.com/c9s/bbgo/releases)並手動下載。 + +自 v2 起,我們添加了一個新的浮點實現 dnum,以支持更高精度的小數。要下載和設置,請參考[Dnum安裝](doc/topics/dnum-binary.md) + +### 一鍵Linode StackScript + +StackScript 允許您一鍵部署一個輕量級實體與 bbgo。 + +- BBGO grid on Binance +- BBGO grid USDT/TWD on MAX +- BBGO grid USDC/TWD on MAX +- BBGO grid LINK/TWD on MAX +- BBGO grid USDC/USDT on MAX +- BBGO grid on MAX +- BBGO bollmaker on Binance + +### 從程式碼構建 +參見[從程式碼構建](./doc/build-from-source.md) + +## 配置 + +添加您的 dotenv 文件: + +```sh +# 針對 Binance 交易所 +BINANCE_API_KEY= +BINANCE_API_SECRET= + +# 如果您想使用 binance.us,將此更改為1 +BINANCE_US=0 + +# 針對 MAX 交易所 +MAX_API_KEY= +MAX_API_SECRET= + +# 針對 OKEx 交易所 +OKEX_API_KEY= +OKEX_API_SECRET= +OKEX_API_PASSPHRASE + +# 針對 Kucoin 交易所 +KUCOIN_API_KEY= +KUCOIN_API_SECRET= +KUCOIN_API_PASSPHRASE= +KUCOIN_API_KEY_VERSION=2 + +# 針對 Bybit 交易所 +BYBIT_API_KEY= +BYBIT_API_SECRET= +``` + +準備您的dotenv文件 `.env.local` 和 BBGO yaml 配置文件 `bbgo.yaml`。 + +要檢查可用的環境變量,請參見[環境變量](./doc/configuration/envvars.md) + +最小的 bbgo.yaml 可以通過以下方式生成: + +```sh +curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml +``` + +要運行策略 + +```sh +bbgo run +``` + +要啟動帶有前端儀表板的 bbgo + +```sh +bbgo run --enable-webserver +``` + +如果您想切換到另一個 dotenv 文件,您可以添加 `--dotenv` 選項或 `--config` : + +```sh +bbgo sync --dotenv .env.dev --config config/grid.yaml --session binance +``` + +要查詢轉賬歷史 + +```sh +bbgo transfer-history --session max --asset USDT --since "2019-01-01" +``` + + + +## 進階配置 + +### 與 Binance 同步系統時間 + + BBGO 提供了用於 UNIX 系統 / 子系統的腳本,以便與 Binance 同步日期。需要事先安裝 jq 和 bc。在 Ubuntu 中安裝相依套件,嘗試以下命令: + +```bash +sudo apt install -y bc jq +``` + +要同步日期,嘗試 + +```bash +sudo ./scripts/sync_time.sh +``` + +您還可以將腳本添加到 crontab 中,這樣系統時間就可以定期與 Binance 同步 + +### Testnet (Paper Trading) + +目前僅支持 [Binance Test Network](https://testnet.binance.vision) + +```bash +export PAPER_TRADE=1 +export DISABLE_MARKET_CACHE=1 # 測試網路支援的市場遠少於主網路 +``` + +### 通知 + +- [設定 Telegram 通知](./doc/configuration/telegram.md) +- [設定 Slack 通知](./doc/configuration/slack.md) + +### 同步交易資料 + +預設情況下, BBGO 不會從交易所同步您的交易資料,因此很難正確計算您的盈虧。 + +通過將交易和訂單同步到本地資料庫,您可以獲得一些好處,如盈虧計算、回測和資產計算。 + +您只能使用一個資料庫驅動程序 MySQL 或 SQLite 來存儲您的交易資料。 + +**注意**:SQLite 不完全支援,我們建議您使用 MySQL 而不是 SQLite。 + +配置 MySQL 資料庫 +要使用 MySQL 資料庫進行資料同步,首先您需要安裝 MySQL 服務器: +#### Configure MySQL Database + +```sh +# Ubuntu Linux +sudo apt-get install -y mysql-server + +# 對於更新的 Ubuntu Linux +sudo apt install -y mysql-server +``` + +或者[在 docker 中執行它](https://hub.docker.com/_/mysql) + +創建您的 mysql 資料庫: + +Create your mysql database: + +```sh +mysql -uroot -e "CREATE DATABASE bbgo CHARSET utf8" +``` + +然後將這些環境變數放入您的 `.env.local` 文件中: + +```sh +DB_DRIVER=mysql +DB_DSN="user:password@tcp(127.0.0.1:3306)/bbgo" +``` + +#### Configure Sqlite3 Database + +配置 Sqlite3 資料庫 +要使用 SQLite3 而不是 MySQL,只需將這些環境變數放入您的 `.env.local` 文件中: + +```sh +DB_DRIVER=sqlite3 +DB_DSN=bbgo.sqlite3 +``` + +## 同步您自己的交易資料 + +一旦您配置了資料庫,您就可以從交易所同步您自己的交易資料。 + +參見[配置私人交易資料同步](./doc/configuration/sync.md) + +## 使用 Redis 在 BBGO session 之間保持持久性 + +要使用 Redis,首先您需要安裝您的 Redis 服務器 + +```sh +# 對於 Ubuntu/Debian Linux +sudo apt-get install -y redis + +# 對於更新的 Ubuntu/Debian Linux +sudo apt install -y redis +``` + +在您的 `bbgo.yaml` 中設定以下環境變數: + +```yaml +persistence: + redis: + host: 127.0.0.1 # 指向您的 Redis 服務器的 IP 地址或主機名,如果與 BBGO 相同則為 127.0.0.1 + port: 6379 # Redis 服務器的端口,預設為 6379 + db: 0 # 使用的 DB 號碼。如果其他應用程序也在使用 Redis,您可以設置為另一個 DB 以避免衝突 +``` + +## 內建策略 + +查看策略目錄 [strategy](pkg/strategy) 以獲得所有內置策略: + +- `pricealert` 策略演示如何使用通知系統 [pricealert](pkg/strategy/pricealert)。參見[文件](./doc/strategy/pricealert.md). +- `buyandhold` 策略演示如何訂閱 kline 事件並提交市場訂單 [buyandhold](pkg/strategy/pricedrop) +- `bollgrid` 策略實現了一個基本的網格策略,使用內置的布林通道指標 [bollgrid](pkg/strategy/bollgrid) +- `grid` 策略實現了固定價格帶網格策略 [grid](pkg/strategy/grid)。參見[文件](./doc/strategy/grid.md). +- `supertrend` 策略使用 Supertrend 指標作為趨勢,並使用 DEMA 指標作為噪聲 +過濾器 [supertrend](pkg/strategy/supertrend)。參見[文件](./doc/strategy/supertrend.md). +- `support` 策略使用具有高交易量的 K 線作為支撐 [support](pkg/strategy/support). 參見[文件](./doc/strategy/support.md). +- `flashcrash` 策略實現了一個捕捉閃崩的策略 [flashcrash](pkg/strategy/flashcrash) +- `marketcap`策略實現了一個基於市場資本化重新平衡投資組合的策略 [marketcap](pkg/strategy/marketcap). 參見[文件](./doc/strategy/marketcap.md). +- `pivotshort` - 以做空為重點的策略。 +- `irr` - 回報率策略。 +- `drift` - 漂移策略。 +- `grid2` - 第二代網格策略。 + +要運行這些內置策略,只需修改配置文件以使配置適合您,例如,如果您想運行 `buyandhold` 策略 + +```sh +vim config/buyandhold.yaml + +# 使用配置運行 bbgo +bbgo run --config config/buyandhold.yaml +``` + +## 回測 + +參考[回測](./doc/topics/back-testing.md) + +## 添加策略 + +參見[開發策略](./doc/topics/developing-strategy.md) + +## 開發您自己的私人策略 + +創建您的 go 包,使用 `go mod`` 初始化存儲庫,並添加 bbgo 作為依賴: + +```sh +go mod init +go get github.com/c9s/bbgo@main +``` + +建立您的 go 套件,使用 go mod 初始化存儲庫,並添加 bbgo 作為依賴: + +```sh +vim strategy.go +``` + +您可以從 獲取策略骨架。 現在添加您的配置 + +```sh +mkdir config +(cd config && curl -o bbgo.yaml https://raw.githubusercontent.com/c9s/bbgo/main/config/minimal.yaml) +``` + +將您的策略包路徑添加到配置文件 `config/bbgo.yaml` + +```yaml +--- +build: + dir: build + imports: + - github.com/your_id/your_swing + targets: + - name: swing-amd64-linux + os: linux + arch: amd64 + - name: swing-amd64-darwin + os: darwin + arch: amd64 +``` + +運行 `bbgo run` 命令,bbgo 將編譯一個導入您策略的包裝 binary 文件: + +```sh +dotenv -f .env.local -- bbgo run --config config/bbgo.yaml +``` + +或者您可以通過以下方式構建您自己的包裝 binary 文件 + +```shell +bbgo build --config config/bbgo.yaml +``` + +參考 +- +- +- +- +- + +## 命令用法 + +### 向特定交易所 session 提交訂單 + +```shell +bbgo submit-order --session=okex --symbol=OKBUSDT --side=buy --price=10.0 --quantity=1 +``` + +### 列出特定交易所 session 的未平倉訂單 + +```sh +bbgo list-orders open --session=okex --symbol=OKBUSDT +bbgo list-orders open --session=max --symbol=MAXUSDT +bbgo list-orders open --session=binance --symbol=BNBUSDT +``` + +### 取消一個未平倉訂單 + +```shell +# 對於 okex,order id 和 symbol 都是必需的 +bbgo cancel-order --session=okex --order-id=318223238325248000 --symbol=OKBUSDT + +# 對於 max,您只需要提供您的 order id +bbgo cancel-order --session=max --order-id=1234566 +``` + +### 除錯用戶資料流 + +```shell +bbgo userdatastream --session okex +bbgo userdatastream --session max +bbgo userdatastream --session binance +``` + +## 動態注入 + +為了最小化策略代碼,bbgo 支持動態依賴注入。 + +在執行您的策略之前,如果 bbgo 發現使用 bbgo 組件的嵌入字段,則會將組件注入到您的策略對象中。例如: + +```go +type Strategy struct { + Symbol string `json:"symbol" + Market types.Market +} +``` + +支援的組件(目前僅限單一交易所策略) + +- `*bbgo.ExchangeSession` +- `bbgo.OrderExecutor` + +如果您的策略中有 `Symbol string` 字段,您的策略將被檢測為基於符號的策略,然後以下類型可以自動注入: + +- `types.Market` + +## 策略執行階段 + +1. 從配置文件加載配置。 +1. 分配並初始化交易所 session 。 +1. 將交易所 session 添加到環境(資料層)。 +1. 使用給定的環境初始化交易者對象(邏輯層)。 +1. 交易者初始化環境並啟動交易所連接。 +1. 依次調用 strategy.Run() 方法。 + +## 交易所 API 範例 + +請查看範例 [examples](examples) + +初始化 MAX API: + +```go +key := os.Getenv("MAX_API_KEY") +secret := os.Getenv("MAX_API_SECRET") + +maxRest := maxapi.NewRestClient(maxapi.ProductionAPIURL) +maxRest.Auth(key, secret) +``` + +創建用戶資料流以獲取訂單簿(深度) + +```go +stream := max.NewStream(key, secret) +stream.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{}) + +streambook := types.NewStreamBook(symbol) +streambook.BindStream(stream) +``` + +## 部署 + +- [Helm Chart](./doc/deployment/helm-chart.md) +- 裸機或 VPS + +## 開發 + +- [添加新交易所](./doc/development/adding-new-exchange.md) +- [遷移](./doc/development/migration.md) + +### 設置您的本地存儲庫 + +1. 點擊 GitHub 儲存庫的 "Fork" 按鈕。 +1. 將你分叉的儲存庫複製到 `$GOPATH/github.com/c9s/bbgo`。 +1. 更改目錄到 `$GOPATH/github.com/c9s/bbgo`。 +1. 創建一個分支並開始你的開發。 +1. 測試你的更改。 +1. 將你的更改推送到你的分叉。 +1. 發送一個拉取請求。 + +### 測試桌面應用 + +對於 webview + +```sh +make embed && go run -tags web ./cmd/bbgo-webview +``` + +對於 lorca + +```sh +make embed && go run -tags web ./cmd/bbgo-lorca +``` + +## 常見問題 + +### 什麼是倉位 ? + +- 基礎貨幣 & 報價貨幣 +- 如何計算平均成本? + +### 尋找新策略? + +你可以寫一篇關於 BBGO 的文章,主題不限,750-1500 字以換取,我可以為你實現策略(取決於複雜性和努力程度)。如果你有興趣,可以在 telegram 或 twitter 私訊我,我們可以討論。 + +### 添加新的加密貨幣交易所支持? + +如果你希望 BBGO 支持一個目前 BBGO 未包含的新加密貨幣交易所,我們可以為你實現。成本是 10 ETH。如果你對此感興趣,請在 telegram 私訊我。 + +## 社群 + +- Telegram +- Telegram (台灣社群) +- Twitter + +## 貢獻 + +參見[貢獻](./CONTRIBUTING.md) + +### 歡迎[抖內](https://opencollective.com/bbgo#backer) + + + +## BBGO 代幣經濟 + +為了支持 BBGO 的開發,我們創建了一個獎勵池來支持貢獻者,通過贈送 $BBG 代幣。查看詳情在 [$BBG 合約頁面](contracts/README.md) 和我們的[官方網站](https://bbgo.finance) + +## 支持者 + +- GitBook + +## 授權 + +AGPL 授權 \ No newline at end of file diff --git a/app.json b/app.json new file mode 100644 index 0000000..e7c72ae --- /dev/null +++ b/app.json @@ -0,0 +1,26 @@ +{ + "name": "bbgo", + "description": "a modern cryptocurrency trading bot", + "repository": "https://github.com/c9s/bbgo", + "keywords": [ + "trading", + "cryptocurrency", + "crypto" + ], + "env": { + "MAX_API_KEY": { + "description": "The API key of your MAX Exchange account" + }, + "MAX_API_SECRET": { + "description": "The API secret of your MAX Exchange account" + } + }, + "buildpacks": [ + { + "url": "heroku/go" + } + ], + "addons": [ + "jawsdb:kitefin" + ] +} diff --git a/apps/backtest-report/.eslintrc.json b/apps/backtest-report/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/apps/backtest-report/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/apps/backtest-report/.gitignore b/apps/backtest-report/.gitignore new file mode 100644 index 0000000..737d872 --- /dev/null +++ b/apps/backtest-report/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo diff --git a/apps/backtest-report/README.md b/apps/backtest-report/README.md new file mode 100644 index 0000000..bc79c74 --- /dev/null +++ b/apps/backtest-report/README.md @@ -0,0 +1,54 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +Install the dependencies: + +``` +yarn install +``` + + +Create a symlink to your back-test report output directory: + +``` +(cd public && ln -s ../../../output output) +``` + + +Generate some back-test reports: + +``` +(cd ../.. && go run ./cmd/bbgo backtest --config bollmaker_ethusdt.yaml --debug --output output --subdir) +``` + +Start the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/backtest-report/components/OrderListTable.tsx b/apps/backtest-report/components/OrderListTable.tsx new file mode 100644 index 0000000..4e075b4 --- /dev/null +++ b/apps/backtest-report/components/OrderListTable.tsx @@ -0,0 +1,81 @@ +import {Button, Checkbox, Group, Table} from "@mantine/core"; +import React, {useState} from "react"; +import {Order} from "../types"; +import moment from "moment"; + +interface OrderListTableProps { + orders: Order[]; + onClick?: (order: Order) => void; + limit?: number; +} + +const OrderListTable = (props: OrderListTableProps) => { + let orders = props.orders; + + const [showCanceledOrders, setShowCanceledOrders] = useState(false); + const [limit, setLimit] = useState(props.limit || 100); + + if (!showCanceledOrders) { + orders = orders.filter((order: Order) => { + return order.status != "CANCELED" + }) + } + + if (orders.length > limit) { + orders = orders.slice(0, limit) + } + + const rows = orders.map((order: Order) => ( + { + props.onClick ? props.onClick(order) : null; + const nodes = e.currentTarget?.parentNode?.querySelectorAll(".selected") + nodes?.forEach((node, i) => { + node.classList.remove("selected") + }) + e.currentTarget.classList.add("selected") + }}> + {order.order_id} + {order.symbol} + {order.side} + {order.order_type} + {order.price} + {order.quantity} + {order.status} + {formatDate(order.creation_time)} + {order.tag} + + )); + + return
+ + setShowCanceledOrders(event.currentTarget.checked)}/> + + + + + + + + + + + + + + + + + {rows} +
Order IDSymbolSideOrder TypePriceQuantityStatusCreation TimeTag
+
+} + +const formatDate = (d : Date) : string => { + return moment(d).format("MMM Do YY hh:mm:ss A Z"); +} + + +export default OrderListTable; diff --git a/apps/backtest-report/components/ReportDetails.tsx b/apps/backtest-report/components/ReportDetails.tsx new file mode 100644 index 0000000..81fa243 --- /dev/null +++ b/apps/backtest-report/components/ReportDetails.tsx @@ -0,0 +1,248 @@ +import React, {useEffect, useState} from 'react'; + +import moment from 'moment'; + +import TradingViewChart from './TradingViewChart'; + +import {BalanceMap, ReportSummary} from "../types"; + +import { + Badge, + Container, + createStyles, + Grid, + Group, + Paper, + SimpleGrid, + Skeleton, + Table, + Text, + ThemeIcon, + Title +} from '@mantine/core'; + +import {ArrowDownRight, ArrowUpRight,} from 'tabler-icons-react'; + +const useStyles = createStyles((theme) => ({ + root: { + paddingTop: theme.spacing.xl * 1.5, + paddingBottom: theme.spacing.xl * 1.5, + }, + + label: { + fontFamily: `Greycliff CF, ${theme.fontFamily}`, + }, +})); + +interface StatsGridIconsProps { + data: { + title: string; + value: string; + diff?: number + dir?: string; + desc?: string; + }[]; +} + +function StatsGridIcons({data}: StatsGridIconsProps) { + const {classes} = useStyles(); + const stats = data.map((stat) => { + const DiffIcon = stat.diff && stat.diff > 0 ? ArrowUpRight : ArrowDownRight; + const DirIcon = stat.dir && stat.dir == "up" ? ArrowUpRight : ArrowDownRight; + + return ( + + +
+ + {stat.title} + {stat.dir ? + ({color: stat.dir == "up" ? theme.colors.teal[6] : theme.colors.red[6]})} + size={16} + radius="xs" + > + + + : null} + + + {stat.value} + +
+ + + {stat.diff ? + ({color: stat.diff && stat.diff > 0 ? theme.colors.teal[6] : theme.colors.red[6]})} + size={38} + radius="md" + > + + + : null} +
+ + {stat.diff ? + + 0 ? 'teal' : 'red'} weight={700}> + {stat.diff}% + {' '} + {stat.diff && stat.diff > 0 ? 'increase' : 'decrease'} compared to last month + : null} + + {stat.desc ? ( + + {stat.desc} + + ) : null} + +
+ ); + }); + + return ( + + {stats} + + ); +} + + +interface ReportDetailsProps { + basePath: string; + runID: string; +} + +const fetchReportSummary = (basePath: string, runID: string) => { + return fetch( + `${basePath}/${runID}/summary.json`, + ) + .then((res) => res.json()) + .catch((e) => { + console.error("failed to fetch index", e) + }); +} + +const skeleton = ; + + +interface BalanceDetailsProps { + balances: BalanceMap; +} + +const BalanceDetails = (props: BalanceDetailsProps) => { + const rows = Object.entries(props.balances).map(([k, v]) => { + return + {k} + {v.available} + ; + }); + + return + + + + + + + {rows} +
CurrencyBalance
; +}; + +const ReportDetails = (props: ReportDetailsProps) => { + const [reportSummary, setReportSummary] = useState() + useEffect(() => { + fetchReportSummary(props.basePath, props.runID).then((summary: ReportSummary) => { + console.log("summary", props.runID, summary); + setReportSummary(summary) + }) + }, [props.runID]) + + if (!reportSummary) { + return
+

Loading {props.runID}

+
; + } + + const strategyName = props.runID.split("_")[1] + const runID = props.runID.split("_").pop() + const totalProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.profit).reduce((prev, cur) => prev + cur) * 100) / 100 + const totalUnrealizedProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.unrealizedProfit).reduce((prev, cur) => prev + cur) * 100) / 100 + const totalTrades = reportSummary.symbolReports.map((report) => report.pnl.numTrades).reduce((prev, cur) => prev + cur) || 0 + + const totalBuyVolume = reportSummary.symbolReports.map((report) => report.pnl.buyVolume).reduce((prev, cur) => prev + cur) || 0 + const totalSellVolume = reportSummary.symbolReports.map((report) => report.pnl.sellVolume).reduce((prev, cur) => prev + cur) || 0 + + const volumeUnit = reportSummary.symbolReports.length == 1 ? reportSummary.symbolReports[0].market.baseCurrency : ''; + + + + // size xl and padding xs + return +
+ Strategy: {strategyName} + {reportSummary.sessions.map((session) => Exchange: {session})} + {reportSummary.symbols.map((symbol) => Symbol: {symbol})} + + {reportSummary.startTime.toString()} — {reportSummary.endTime.toString()} ~ { + moment.duration((new Date(reportSummary.endTime)).getTime() - (new Date(reportSummary.startTime)).getTime()).humanize() + } + Run ID: {runID} +
+ = 0 ? "up" : "down"}, + { + title: "Unr. Profit", + value: totalUnrealizedProfit.toString() + "$", + dir: totalUnrealizedProfit > 0 ? "up" : "down" + }, + {title: "Trades", value: totalTrades.toString()}, + {title: "Buy Vol", value: totalBuyVolume.toString() + ` ${volumeUnit}`}, + {title: "Sell Vol", value: totalSellVolume.toString() + ` ${volumeUnit}`}, + ]}/> + + + + Initial Total Balances + + + + Final Total Balances + + + + + { + /* + + + + + {skeleton} + + */ + } +
+ { + reportSummary.symbols.map((symbol: string, i: number) => { + return + }) + } +
+ +
; +}; + + +export default ReportDetails; diff --git a/apps/backtest-report/components/ReportNavigator.tsx b/apps/backtest-report/components/ReportNavigator.tsx new file mode 100644 index 0000000..55e16d3 --- /dev/null +++ b/apps/backtest-report/components/ReportNavigator.tsx @@ -0,0 +1,79 @@ +import React, {useEffect, useState} from 'react'; +import {List, ThemeIcon} from '@mantine/core'; +import {CircleCheck} from 'tabler-icons-react'; + +import {ReportEntry, ReportIndex} from '../types'; + +function fetchIndex(basePath: string, setter: (data: any) => void) { + return fetch( + `${basePath}/index.json`, + ) + .then((res) => res.json()) + .then((data) => { + console.log("reportIndex", data); + data.runs.reverse() // last reports render first + setter(data); + }) + .catch((e) => { + console.error("failed to fetch index", e) + }); +} + +interface ReportNavigatorProps { + onSelect: (reportEntry: ReportEntry) => void; +} + +const ReportNavigator = (props: ReportNavigatorProps) => { + const [isLoading, setLoading] = useState(false) + const [reportIndex, setReportIndex] = useState({runs: []}); + + useEffect(() => { + setLoading(true) + fetchIndex('/output', setReportIndex).then(() => { + setLoading(false); + }) + }, []); + + if (isLoading) { + return
Loading...
; + } + + if (reportIndex.runs.length == 0) { + return
No back-test report data
+ } + + return
+ + + + } + > + { + reportIndex.runs.map((entry) => { + return { + if (props.onSelect) { + props.onSelect(entry); + } + }}> +
+ {entry.id} +
+
+ }) + } +
+
; + + +}; + +export default ReportNavigator; diff --git a/apps/backtest-report/components/TimeRangeSlider/components/Handle.js b/apps/backtest-report/components/TimeRangeSlider/components/Handle.js new file mode 100644 index 0000000..338fb01 --- /dev/null +++ b/apps/backtest-report/components/TimeRangeSlider/components/Handle.js @@ -0,0 +1,44 @@ +import PropTypes from 'prop-types' +import React from 'react' + +const Handle = ({ + error, + domain: [min, max], + handle: { id, value, percent = 0 }, + disabled, + getHandleProps, + }) => { + const leftPosition = `${percent}%` + + return ( + <> +
+
+
+
+ + ) +} + +Handle.propTypes = { + domain: PropTypes.array.isRequired, + handle: PropTypes.shape({ + id: PropTypes.string.isRequired, + value: PropTypes.number.isRequired, + percent: PropTypes.number.isRequired + }).isRequired, + getHandleProps: PropTypes.func.isRequired, + disabled: PropTypes.bool, + style: PropTypes.object, +} + +Handle.defaultProps = { disabled: false } + +export default Handle diff --git a/apps/backtest-report/components/TimeRangeSlider/components/KeyboardHandle.js b/apps/backtest-report/components/TimeRangeSlider/components/KeyboardHandle.js new file mode 100644 index 0000000..077312b --- /dev/null +++ b/apps/backtest-report/components/TimeRangeSlider/components/KeyboardHandle.js @@ -0,0 +1,32 @@ +import PropTypes from 'prop-types' +import React from 'react' + +const KeyboardHandle = ({ domain: [min, max], handle: { id, value, percent = 0 }, disabled, getHandleProps }) => ( + + + + + +
+ + {testResponse ? ( + testResponse.error ? ( + + {testResponse.error} + + ) : testResponse.success ? ( + + Connection Test Succeeded + + ) : null + ) : null} + + {response ? ( + response.error ? ( + + {response.error} + + ) : response.success ? ( + + Exchange Session Added + + ) : null + ) : null} + + ); +} diff --git a/apps/frontend/components/ConfigureDatabaseForm.js b/apps/frontend/components/ConfigureDatabaseForm.js new file mode 100644 index 0000000..1b3d7ce --- /dev/null +++ b/apps/frontend/components/ConfigureDatabaseForm.js @@ -0,0 +1,209 @@ +import React from 'react'; +import Grid from '@mui/material/Grid'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; +import TextField from '@mui/material/TextField'; +import FormHelperText from '@mui/material/FormHelperText'; +import Radio from '@mui/material/Radio'; +import RadioGroup from '@mui/material/RadioGroup'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import FormControl from '@mui/material/FormControl'; +import FormLabel from '@mui/material/FormLabel'; + +import Alert from '@mui/lab/Alert'; + +import { configureDatabase, testDatabaseConnection } from '../api/bbgo'; + +import { makeStyles } from '@mui/styles'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + minWidth: 120, + }, + buttons: { + display: 'flex', + justifyContent: 'flex-end', + marginTop: theme.spacing(2), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + '& > *': { + marginLeft: theme.spacing(1), + }, + }, +})); + +export default function ConfigureDatabaseForm({ onConfigured }) { + const classes = useStyles(); + + const [mysqlURL, setMysqlURL] = React.useState( + 'root@tcp(127.0.0.1:3306)/bbgo' + ); + + const [driver, setDriver] = React.useState('sqlite3'); + const [testing, setTesting] = React.useState(false); + const [testResponse, setTestResponse] = React.useState(null); + const [configured, setConfigured] = React.useState(false); + + const getDSN = () => (driver === 'sqlite3' ? 'file:bbgo.sqlite3' : mysqlURL); + + const resetTestResponse = () => { + setTestResponse(null); + }; + + const handleConfigureDatabase = (event) => { + const dsn = getDSN(); + + configureDatabase({ driver, dsn }, (response) => { + console.log(response); + setTesting(false); + setTestResponse(response); + if (onConfigured) { + setConfigured(true); + setTimeout(onConfigured, 3000); + } + }).catch((err) => { + console.error(err); + setTesting(false); + setTestResponse(err.response.data); + }); + }; + + const handleTestConnection = (event) => { + const dsn = getDSN(); + + setTesting(true); + testDatabaseConnection({ driver, dsn }, (response) => { + console.log(response); + setTesting(false); + setTestResponse(response); + }).catch((err) => { + console.error(err); + setTesting(false); + setTestResponse(err.response.data); + }); + }; + + return ( + + + Configure Database + + + + If you have database installed on your machine, you can enter the DSN + string in the following field. Please note this is optional, you CAN + SKIP this step. + + + + + + + Database Driver + { + setDriver(event.target.value); + }} + > + } + label="Standard (Default)" + /> + } + label="MySQL" + /> + + + + + + + {driver === 'mysql' ? ( + + { + setMysqlURL(event.target.value); + resetTestResponse(); + }} + /> + MySQL DSN + + + If you have database installed on your machine, you can enter the + DSN string like the following format: +
+
+                root:password@tcp(127.0.0.1:3306)/bbgo
+              
+
+ Be sure to create your database before using it. You need to + execute the following statement to create a database: +
+
+                CREATE DATABASE bbgo CHARSET utf8;
+              
+
+
+ ) : ( + + + + If you don't know what to choose, just pick the standard driver + (sqlite3). +
+ For professionals, you can pick MySQL driver, BBGO works best + with MySQL, especially for larger data scale. +
+
+
+ )} +
+ +
+ + + +
+ + {testResponse ? ( + testResponse.error ? ( + + {testResponse.error} + + ) : testResponse.success ? ( + + Connection Test Succeeded + + ) : null + ) : null} +
+ ); +} diff --git a/apps/frontend/components/ConfigureGridStrategyForm.js b/apps/frontend/components/ConfigureGridStrategyForm.js new file mode 100644 index 0000000..2305671 --- /dev/null +++ b/apps/frontend/components/ConfigureGridStrategyForm.js @@ -0,0 +1,446 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import Grid from '@mui/material/Grid'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; + +import { makeStyles } from '@mui/styles'; +import { + attachStrategyOn, + querySessions, + querySessionSymbols, +} from '../api/bbgo'; + +import TextField from '@mui/material/TextField'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import FormHelperText from '@mui/material/FormHelperText'; +import InputLabel from '@mui/material/InputLabel'; +import FormControl from '@mui/material/FormControl'; +import Radio from '@mui/material/Radio'; +import RadioGroup from '@mui/material/RadioGroup'; +import FormLabel from '@mui/material/FormLabel'; +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; + +import Alert from '@mui/lab/Alert'; +import Box from '@mui/material/Box'; + +import NumberFormat from 'react-number-format'; + +function parseFloatValid(s) { + if (s) { + const f = parseFloat(s); + if (!isNaN(f)) { + return f; + } + } + + return null; +} + +function parseFloatCall(s, cb) { + if (s) { + const f = parseFloat(s); + if (!isNaN(f)) { + cb(f); + } + } +} + +function StandardNumberFormat(props) { + const { inputRef, onChange, ...other } = props; + return ( + { + onChange({ + target: { + name: props.name, + value: values.value, + }, + }); + }} + thousandSeparator + isNumericString + /> + ); +} + +StandardNumberFormat.propTypes = { + inputRef: PropTypes.func.isRequired, + name: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, +}; + +function PriceNumberFormat(props) { + const { inputRef, onChange, ...other } = props; + + return ( + { + onChange({ + target: { + name: props.name, + value: values.value, + }, + }); + }} + thousandSeparator + isNumericString + prefix="$" + /> + ); +} + +PriceNumberFormat.propTypes = { + inputRef: PropTypes.func.isRequired, + name: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, +}; + +const useStyles = makeStyles((theme) => ({ + formControl: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + minWidth: 120, + }, + buttons: { + display: 'flex', + justifyContent: 'flex-end', + marginTop: theme.spacing(2), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + '& > *': { + marginLeft: theme.spacing(1), + }, + }, +})); + +export default function ConfigureGridStrategyForm({ onBack, onAdded }) { + const classes = useStyles(); + + const [errors, setErrors] = React.useState({}); + + const [sessions, setSessions] = React.useState([]); + + const [activeSessionSymbols, setActiveSessionSymbols] = React.useState([]); + + const [selectedSessionName, setSelectedSessionName] = React.useState(null); + + const [selectedSymbol, setSelectedSymbol] = React.useState(''); + + const [quantityBy, setQuantityBy] = React.useState('fixedAmount'); + + const [upperPrice, setUpperPrice] = React.useState(30000.0); + const [lowerPrice, setLowerPrice] = React.useState(10000.0); + + const [fixedAmount, setFixedAmount] = React.useState(100.0); + const [fixedQuantity, setFixedQuantity] = React.useState(1.234); + const [gridNumber, setGridNumber] = React.useState(20); + const [profitSpread, setProfitSpread] = React.useState(100.0); + + const [response, setResponse] = React.useState({}); + + React.useEffect(() => { + querySessions((sessions) => { + setSessions(sessions); + }); + }, []); + + const handleAdd = (event) => { + const payload = { + symbol: selectedSymbol, + gridNumber: parseFloatValid(gridNumber), + profitSpread: parseFloatValid(profitSpread), + upperPrice: parseFloatValid(upperPrice), + lowerPrice: parseFloatValid(lowerPrice), + }; + switch (quantityBy) { + case 'fixedQuantity': + payload.quantity = parseFloatValid(fixedQuantity); + break; + + case 'fixedAmount': + payload.amount = parseFloatValid(fixedAmount); + break; + } + + if (!selectedSessionName) { + setErrors({ session: true }); + return; + } + + if (!selectedSymbol) { + setErrors({ symbol: true }); + return; + } + + console.log(payload); + attachStrategyOn(selectedSessionName, 'grid', payload, (response) => { + console.log(response); + setResponse(response); + if (onAdded) { + setTimeout(onAdded, 3000); + } + }) + .catch((err) => { + console.error(err); + setResponse(err.response.data); + }) + .finally(() => { + setErrors({}); + }); + }; + + const handleQuantityBy = (event) => { + setQuantityBy(event.target.value); + }; + + const handleSessionChange = (event) => { + const sessionName = event.target.value; + setSelectedSessionName(sessionName); + + querySessionSymbols(sessionName, (symbols) => { + setActiveSessionSymbols(symbols); + }).catch((err) => { + console.error(err); + setResponse(err.response.data); + }); + }; + + const sessionMenuItems = sessions.map((session, index) => { + return ( + + {session.name} + + ); + }); + + const symbolMenuItems = activeSessionSymbols.map((symbol, index) => { + return ( + + {symbol} + + ); + }); + + return ( + + + Add Grid Strategy + + + + Fixed price band grid strategy uses the fixed price band to place + buy/sell orders. This strategy places sell orders above the current + price, places buy orders below the current price. If any of the order is + executed, then it will automatically place a new profit order on the + reverse side. + + + + + + Session + + + + Select the exchange session you want to mount this strategy. + + + + + + Market + + + + Select the market you want to run this strategy + + + + + { + parseFloatCall(event.target.value, setUpperPrice); + }} + value={upperPrice} + InputProps={{ + inputComponent: PriceNumberFormat, + }} + /> + + + + { + parseFloatCall(event.target.value, setLowerPrice); + }} + value={lowerPrice} + InputProps={{ + inputComponent: PriceNumberFormat, + }} + /> + + + + { + parseFloatCall(event.target.value, setProfitSpread); + }} + value={profitSpread} + InputProps={{ + inputComponent: StandardNumberFormat, + }} + /> + + + + + Order Quantity By + + } + label="Fixed Amount" + /> + } + label="Fixed Quantity" + /> + + + + + + {quantityBy === 'fixedQuantity' ? ( + { + parseFloatCall(event.target.value, setFixedQuantity); + }} + value={fixedQuantity} + InputProps={{ + inputComponent: StandardNumberFormat, + }} + /> + ) : null} + + {quantityBy === 'fixedAmount' ? ( + { + parseFloatCall(event.target.value, setFixedAmount); + }} + value={fixedAmount} + InputProps={{ + inputComponent: PriceNumberFormat, + }} + /> + ) : null} + + + + { + parseFloatCall(event.target.value, setGridNumber); + }} + value={gridNumber} + InputProps={{ + inputComponent: StandardNumberFormat, + }} + /> + + + +
+ + + +
+ + {response ? ( + response.error ? ( + + {response.error} + + ) : response.success ? ( + + Strategy Added + + ) : null + ) : null} +
+ ); +} diff --git a/apps/frontend/components/ConnectWallet.js b/apps/frontend/components/ConnectWallet.js new file mode 100644 index 0000000..e68eaf7 --- /dev/null +++ b/apps/frontend/components/ConnectWallet.js @@ -0,0 +1,143 @@ +import React from 'react'; + +import { makeStyles } from '@mui/styles'; + +import Button from '@mui/material/Button'; +import ClickAwayListener from '@mui/material/ClickAwayListener'; +import Grow from '@mui/material/Grow'; +import Paper from '@mui/material/Paper'; +import Popper from '@mui/material/Popper'; +import MenuItem from '@mui/material/MenuItem'; +import MenuList from '@mui/material/MenuList'; +import ListItemText from '@mui/material/ListItemText'; +import PersonIcon from '@mui/icons-material/Person'; + +import { useEtherBalance, useTokenBalance, useEthers } from '@usedapp/core'; +import { formatEther } from '@ethersproject/units'; + +const useStyles = makeStyles((theme) => ({ + buttons: { + margin: theme.spacing(1), + padding: theme.spacing(1), + }, + profile: { + margin: theme.spacing(1), + padding: theme.spacing(1), + }, +})); + +const BBG = '0x3Afe98235d680e8d7A52e1458a59D60f45F935C0'; + +export default function ConnectWallet() { + const classes = useStyles(); + + const { activateBrowserWallet, account } = useEthers(); + const etherBalance = useEtherBalance(account); + const tokenBalance = useTokenBalance(BBG, account); + + const [open, setOpen] = React.useState(false); + const anchorRef = React.useRef(null); + + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + + setOpen(false); + }; + + function handleListKeyDown(event) { + if (event.key === 'Tab') { + event.preventDefault(); + setOpen(false); + } else if (event.key === 'Escape') { + setOpen(false); + } + } + + // return focus to the button when we transitioned from !open -> open + const prevOpen = React.useRef(open); + React.useEffect(() => { + if (prevOpen.current === true && open === false) { + anchorRef.current.focus(); + } + + prevOpen.current = open; + }, [open]); + + return ( + <> + {account ? ( + <> + + + {({ TransitionProps, placement }) => ( + + + + + + {account &&

Account: {account}

} +
+ + {etherBalance && ( + ETH Balance: {formatEther(etherBalance)} + )} + + + {tokenBalance && ( + BBG Balance: {formatEther(tokenBalance)} + )} + +
+
+
+
+ )} +
+ + ) : ( +
+ +
+ )} + + ); +} diff --git a/apps/frontend/components/Detail.tsx b/apps/frontend/components/Detail.tsx new file mode 100644 index 0000000..79f4ed7 --- /dev/null +++ b/apps/frontend/components/Detail.tsx @@ -0,0 +1,56 @@ +import { styled } from '@mui/styles'; +import type { GridStrategy } from '../api/bbgo'; + +import RunningTime from './RunningTime'; +import Summary from './Summary'; +import Stats from './Stats'; + +const StrategyContainer = styled('section')(() => ({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-around', + width: '350px', + border: '1px solid rgb(248, 149, 35)', + borderRadius: '10px', + padding: '10px', +})); + +const Strategy = styled('div')(() => ({ + fontSize: '20px', +})); + +export const Description = styled('div')(() => ({ + color: 'rgb(140, 140, 140)', + '& .duration': { + marginLeft: '3px', + }, +})); + +export default function Detail({ data }: { data: GridStrategy }) { + const { strategy, stats, startTime } = data; + const totalProfitsPercentage = (stats.totalProfits / stats.investment) * 100; + const gridProfitsPercentage = (stats.gridProfits / stats.investment) * 100; + const gridAprPercentage = (stats.gridProfits / 5) * 365; + + const now = Date.now(); + const durationMilliseconds = now - startTime; + const seconds = durationMilliseconds / 1000; + + return ( + + {strategy} +
{data[strategy].symbol}
+ + + 0 arbitrages in 24 hours / Total {stats.totalArbs}{' '} + arbitrages + + + + + ); +} diff --git a/apps/frontend/components/ExchangeSessionTabPanel.js b/apps/frontend/components/ExchangeSessionTabPanel.js new file mode 100644 index 0000000..fb76f44 --- /dev/null +++ b/apps/frontend/components/ExchangeSessionTabPanel.js @@ -0,0 +1,49 @@ +import Paper from '@mui/material/Paper'; +import Tabs from '@mui/material/Tabs'; +import Tab from '@mui/material/Tab'; +import React, { useEffect, useState } from 'react'; +import { querySessions } from '../api/bbgo'; +import Typography from '@mui/material/Typography'; +import { makeStyles } from '@mui/styles'; + +const useStyles = makeStyles((theme) => ({ + paper: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, +})); + +export default function ExchangeSessionTabPanel() { + const classes = useStyles(); + + const [tabIndex, setTabIndex] = React.useState(0); + const handleTabClick = (event, newValue) => { + setTabIndex(newValue); + }; + + const [sessions, setSessions] = useState([]); + + useEffect(() => { + querySessions((sessions) => { + setSessions(sessions); + }); + }, []); + + return ( + + + Sessions + + + {sessions.map((session) => { + return ; + })} + + + ); +} diff --git a/apps/frontend/components/ReviewSessions.js b/apps/frontend/components/ReviewSessions.js new file mode 100644 index 0000000..6eb49c7 --- /dev/null +++ b/apps/frontend/components/ReviewSessions.js @@ -0,0 +1,88 @@ +import React from 'react'; +import Grid from '@mui/material/Grid'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import PowerIcon from '@mui/icons-material/Power'; + +import { makeStyles } from '@mui/styles'; +import { querySessions } from '../api/bbgo'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + minWidth: 120, + }, + buttons: { + display: 'flex', + justifyContent: 'flex-end', + marginTop: theme.spacing(2), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + '& > *': { + marginLeft: theme.spacing(1), + }, + }, +})); + +export default function ReviewSessions({ onBack, onNext }) { + const classes = useStyles(); + + const [sessions, setSessions] = React.useState([]); + + React.useEffect(() => { + querySessions((sessions) => { + setSessions(sessions); + }); + }, []); + + const items = sessions.map((session, i) => { + console.log(session); + return ( + + + + + + + ); + }); + + return ( + + + Review Sessions + + + {items} + +
+ + + +
+
+ ); +} diff --git a/apps/frontend/components/ReviewStrategies.js b/apps/frontend/components/ReviewStrategies.js new file mode 100644 index 0000000..085fabe --- /dev/null +++ b/apps/frontend/components/ReviewStrategies.js @@ -0,0 +1,157 @@ +import React from 'react'; +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; +import List from '@mui/material/List'; +import Card from '@mui/material/Card'; +import CardHeader from '@mui/material/CardHeader'; +import CardContent from '@mui/material/CardContent'; +import Avatar from '@mui/material/Avatar'; +import IconButton from '@mui/material/IconButton'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; + +import { makeStyles } from '@mui/styles'; +import { queryStrategies } from '../api/bbgo'; + +const useStyles = makeStyles((theme) => ({ + strategyCard: { + margin: theme.spacing(1), + }, + formControl: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + minWidth: 120, + }, + buttons: { + display: 'flex', + justifyContent: 'flex-end', + marginTop: theme.spacing(2), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + '& > *': { + marginLeft: theme.spacing(1), + }, + }, +})); + +function configToTable(config) { + const rows = Object.getOwnPropertyNames(config).map((k) => { + return { + key: k, + val: config[k], + }; + }); + + return ( + + + + + Field + Value + + + + {rows.map((row) => ( + + + {row.key} + + {row.val} + + ))} + +
+
+ ); +} + +export default function ReviewStrategies({ onBack, onNext }) { + const classes = useStyles(); + + const [strategies, setStrategies] = React.useState([]); + + React.useEffect(() => { + queryStrategies((strategies) => { + setStrategies(strategies || []); + }).catch((err) => { + console.error(err); + }); + }, []); + + const items = strategies.map((o, i) => { + const mounts = o.on || []; + delete o.on; + + const config = o[o.strategy]; + + const titleComps = [o.strategy.toUpperCase()]; + if (config.symbol) { + titleComps.push(config.symbol); + } + + const title = titleComps.join(' '); + + return ( + + G} + action={ + + + + } + title={title} + subheader={`Exchange ${mounts.map((m) => m.toUpperCase())}`} + /> + + + Strategy will be executed on session {mounts.join(',')} with the + following configuration: + + + {configToTable(config)} + + + ); + }); + + return ( + + + Review Strategies + + + {items} + +
+ + + +
+
+ ); +} diff --git a/apps/frontend/components/RunningTime.tsx b/apps/frontend/components/RunningTime.tsx new file mode 100644 index 0000000..07e21c1 --- /dev/null +++ b/apps/frontend/components/RunningTime.tsx @@ -0,0 +1,34 @@ +import { styled } from '@mui/styles'; +import { Description } from './Detail'; + +const RunningTimeSection = styled('div')(() => ({ + display: 'flex', + alignItems: 'center', +})); + +const StatusSign = styled('span')(() => ({ + width: '10px', + height: '10px', + display: 'block', + backgroundColor: 'rgb(113, 218, 113)', + borderRadius: '50%', + marginRight: '5px', +})); + +export default function RunningTime({ seconds }: { seconds: number }) { + const day = Math.floor(seconds / (60 * 60 * 24)); + const hour = Math.floor((seconds % (60 * 60 * 24)) / 3600); + const min = Math.floor(((seconds % (60 * 60 * 24)) % 3600) / 60); + + return ( + + + + Running for + {day}D + {hour}H + {min}M + + + ); +} diff --git a/apps/frontend/components/SaveConfigAndRestart.js b/apps/frontend/components/SaveConfigAndRestart.js new file mode 100644 index 0000000..86350ab --- /dev/null +++ b/apps/frontend/components/SaveConfigAndRestart.js @@ -0,0 +1,105 @@ +import React from 'react'; +import { useRouter } from 'next/router'; + +import Button from '@mui/material/Button'; +import Typography from '@mui/material/Typography'; + +import { makeStyles } from '@mui/styles'; + +import { ping, saveConfig, setupRestart } from '../api/bbgo'; +import Box from '@mui/material/Box'; +import Alert from '@mui/lab/Alert'; + +const useStyles = makeStyles((theme) => ({ + strategyCard: { + margin: theme.spacing(1), + }, + formControl: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + minWidth: 120, + }, + buttons: { + display: 'flex', + justifyContent: 'flex-end', + marginTop: theme.spacing(2), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), + '& > *': { + marginLeft: theme.spacing(1), + }, + }, +})); + +export default function SaveConfigAndRestart({ onBack, onRestarted }) { + const classes = useStyles(); + + const { push } = useRouter(); + const [response, setResponse] = React.useState({}); + + const handleRestart = () => { + saveConfig((resp) => { + setResponse(resp); + + setupRestart((resp) => { + let t; + t = setInterval(() => { + ping(() => { + clearInterval(t); + push('/'); + }); + }, 1000); + }).catch((err) => { + console.error(err); + setResponse(err.response.data); + }); + + // call restart here + }).catch((err) => { + console.error(err); + setResponse(err.response.data); + }); + }; + + return ( + + + Save Config and Restart + + + + Click "Save and Restart" to save the configurations to the config file{' '} + bbgo.yaml, and save the exchange session credentials to the + dotenv file .env.local. + + +
+ + + +
+ + {response ? ( + response.error ? ( + + {response.error} + + ) : response.success ? ( + + Config Saved + + ) : null + ) : null} +
+ ); +} diff --git a/apps/frontend/components/SideBar.js b/apps/frontend/components/SideBar.js new file mode 100644 index 0000000..e491099 --- /dev/null +++ b/apps/frontend/components/SideBar.js @@ -0,0 +1,103 @@ +import Drawer from '@mui/material/Drawer'; +import Divider from '@mui/material/Divider'; +import List from '@mui/material/List'; +import Link from 'next/link'; +import ListItem from '@mui/material/ListItem'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import DashboardIcon from '@mui/icons-material/Dashboard'; +import ListItemText from '@mui/material/ListItemText'; +import ListIcon from '@mui/icons-material/List'; +import TrendingUpIcon from '@mui/icons-material/TrendingUp'; +import React from 'react'; +import { makeStyles } from '@mui/styles'; + +const drawerWidth = 240; + +const useStyles = makeStyles((theme) => ({ + root: { + flexGrow: 1, + display: 'flex', + }, + toolbar: { + paddingRight: 24, // keep right padding when drawer closed + }, + toolbarIcon: { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + padding: '0 8px', + ...theme.mixins.toolbar, + }, + appBarSpacer: theme.mixins.toolbar, + drawerPaper: { + [theme.breakpoints.up('sm')]: { + width: drawerWidth, + flexShrink: 0, + }, + position: 'relative', + whiteSpace: 'nowrap', + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + }, + drawer: { + width: drawerWidth, + }, +})); + +export default function SideBar() { + const classes = useStyles(); + + return ( + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/frontend/components/Stats.tsx b/apps/frontend/components/Stats.tsx new file mode 100644 index 0000000..bd34bde --- /dev/null +++ b/apps/frontend/components/Stats.tsx @@ -0,0 +1,51 @@ +import { styled } from '@mui/styles'; +import { StatsTitle, StatsValue, Percentage } from './Summary'; +import { GridStats } from '../api/bbgo'; + +const StatsSection = styled('div')(() => ({ + display: 'grid', + gridTemplateColumns: '1fr 1fr 1fr', + gap: '10px', +})); + +export default function Stats({ + stats, + gridProfitsPercentage, + gridAprPercentage, +}: { + stats: GridStats; + gridProfitsPercentage: number; + gridAprPercentage: number; +}) { + return ( + +
+ Grid Profits + {stats.gridProfits} + {gridProfitsPercentage}% +
+ +
+ Floating PNL + {stats.floatingPNL} +
+ +
+ Grid APR + {gridAprPercentage}% +
+ +
+ Current Price +
{stats.currentPrice}
+
+ +
+ Price Range +
+ {stats.lowestPrice}~{stats.highestPrice} +
+
+
+ ); +} diff --git a/apps/frontend/components/Summary.tsx b/apps/frontend/components/Summary.tsx new file mode 100644 index 0000000..a91435f --- /dev/null +++ b/apps/frontend/components/Summary.tsx @@ -0,0 +1,50 @@ +import { styled } from '@mui/styles'; +import { GridStats } from '../api/bbgo'; + +const SummarySection = styled('div')(() => ({ + width: '100%', + display: 'flex', + justifyContent: 'space-around', + backgroundColor: 'rgb(255, 245, 232)', + margin: '10px 0', +})); + +const SummaryBlock = styled('div')(() => ({ + padding: '5px 0 5px 0', +})); + +export const StatsTitle = styled('div')(() => ({ + margin: '0 0 10px 0', +})); + +export const StatsValue = styled('div')(() => ({ + marginBottom: '10px', + color: 'rgb(123, 169, 90)', +})); + +export const Percentage = styled('div')(() => ({ + color: 'rgb(123, 169, 90)', +})); + +export default function Summary({ + stats, + totalProfitsPercentage, +}: { + stats: GridStats; + totalProfitsPercentage: number; +}) { + return ( + + + Investment USDT +
{stats.investment}
+
+ + + Total Profit USDT + {stats.totalProfits} + {totalProfitsPercentage}% + +
+ ); +} diff --git a/apps/frontend/components/SyncButton.tsx b/apps/frontend/components/SyncButton.tsx new file mode 100644 index 0000000..de00aac --- /dev/null +++ b/apps/frontend/components/SyncButton.tsx @@ -0,0 +1,39 @@ +import { styled } from '@mui/styles'; +import React, { useEffect, useState } from 'react'; +import { querySyncStatus, SyncStatus, triggerSync } from '../api/bbgo'; +import useInterval from '../hooks/useInterval'; + +const ToolbarButton = styled('button')(({ theme }) => ({ + padding: theme.spacing(1), +})); + +export default function SyncButton() { + const [syncing, setSyncing] = useState(false); + + const sync = async () => { + try { + setSyncing(true); + await triggerSync(); + } catch { + setSyncing(false); + } + }; + + useEffect(() => { + sync(); + }, []); + + useInterval(() => { + querySyncStatus().then((s) => { + if (s !== SyncStatus.Syncing) { + setSyncing(false); + } + }); + }, 2000); + + return ( + + {syncing ? 'Syncing...' : 'Sync'} + + ); +} diff --git a/apps/frontend/components/TotalAssetsDetails.js b/apps/frontend/components/TotalAssetsDetails.js new file mode 100644 index 0000000..b587b72 --- /dev/null +++ b/apps/frontend/components/TotalAssetsDetails.js @@ -0,0 +1,87 @@ +import React from 'react'; +import CardContent from '@mui/material/CardContent'; +import Card from '@mui/material/Card'; +import { makeStyles } from '@mui/styles'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemAvatar from '@mui/material/ListItemAvatar'; +import Avatar from '@mui/material/Avatar'; + +const useStyles = makeStyles((theme) => ({ + root: { + margin: theme.spacing(1), + }, + cardContent: {}, +})); + +const logoCurrencies = { + BTC: true, + ETH: true, + BCH: true, + LTC: true, + USDT: true, + BNB: true, + COMP: true, + XRP: true, + LINK: true, + DOT: true, + SXP: true, + DAI: true, + MAX: true, + TWD: true, + SNT: true, + YFI: true, + GRT: true, +}; + +export default function TotalAssetsDetails({ assets }) { + const classes = useStyles(); + + const sortedAssets = []; + for (let k in assets) { + sortedAssets.push(assets[k]); + } + sortedAssets.sort((a, b) => { + if (a.inUSD > b.inUSD) { + return -1; + } + + if (a.inUSD < b.inUSD) { + return 1; + } + + return 0; + }); + + const items = sortedAssets.map((a) => { + return ( + + {a.currency in logoCurrencies ? ( + + + + ) : ( + + + + )} + + + ); + }); + + return ( + + + {items} + + + ); +} diff --git a/apps/frontend/components/TotalAssetsPie.js b/apps/frontend/components/TotalAssetsPie.js new file mode 100644 index 0000000..695b8da --- /dev/null +++ b/apps/frontend/components/TotalAssetsPie.js @@ -0,0 +1,94 @@ +import React, { useEffect, useState } from 'react'; + +import { ResponsivePie } from '@nivo/pie'; +import { queryAssets } from '../api/bbgo'; +import { currencyColor } from '../src/utils'; +import CardContent from '@mui/material/CardContent'; +import Card from '@mui/material/Card'; +import { makeStyles } from '@mui/styles'; + +function reduceAssetsBy(assets, field, minimum) { + let as = []; + + let others = { id: 'others', labels: 'others', value: 0.0 }; + for (let key in assets) { + if (assets[key]) { + let a = assets[key]; + let value = a[field]; + + if (value < minimum) { + others.value += value; + } else { + as.push({ + id: a.currency, + label: a.currency, + color: currencyColor(a.currency), + value: Math.round(value, 1), + }); + } + } + } + + return as; +} + +const useStyles = makeStyles((theme) => ({ + root: { + margin: theme.spacing(1), + }, + cardContent: { + height: 350, + }, +})); + +export default function TotalAssetsPie({ assets }) { + const classes = useStyles(); + return ( + + + + + + ); +} diff --git a/apps/frontend/components/TotalAssetsSummary.js b/apps/frontend/components/TotalAssetsSummary.js new file mode 100644 index 0000000..f0d4110 --- /dev/null +++ b/apps/frontend/components/TotalAssetsSummary.js @@ -0,0 +1,60 @@ +import { useEffect, useState } from 'react'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import Typography from '@mui/material/Typography'; +import { makeStyles } from '@mui/styles'; + +function aggregateAssetsBy(assets, field) { + let total = 0.0; + for (let key in assets) { + if (assets[key]) { + let a = assets[key]; + let value = a[field]; + total += value; + } + } + + return total; +} + +const useStyles = makeStyles((theme) => ({ + root: { + margin: theme.spacing(1), + }, + title: { + fontSize: 14, + }, + pos: { + marginTop: 12, + }, +})); + +export default function TotalAssetSummary({ assets }) { + const classes = useStyles(); + return ( + + + + Total Account Balance + + + {Math.round(aggregateAssetsBy(assets, 'inBTC') * 1e8) / 1e8}{' '} + BTC + + + + Estimated Value + + + + {Math.round(aggregateAssetsBy(assets, 'inUSD') * 100) / 100}{' '} + USD + + + + ); +} diff --git a/apps/frontend/components/TradingVolumeBar.js b/apps/frontend/components/TradingVolumeBar.js new file mode 100644 index 0000000..b9b0773 --- /dev/null +++ b/apps/frontend/components/TradingVolumeBar.js @@ -0,0 +1,161 @@ +import { ResponsiveBar } from '@nivo/bar'; +import { queryTradingVolume } from '../api/bbgo'; +import { useEffect, useState } from 'react'; + +function toPeriodDateString(time, period) { + switch (period) { + case 'day': + return ( + time.getFullYear() + '-' + (time.getMonth() + 1) + '-' + time.getDate() + ); + case 'month': + return time.getFullYear() + '-' + (time.getMonth() + 1); + case 'year': + return time.getFullYear(); + } + + return ( + time.getFullYear() + '-' + (time.getMonth() + 1) + '-' + time.getDate() + ); +} + +function groupData(rows, period, segment) { + let dateIndex = {}; + let startTime = null; + let endTime = null; + let keys = {}; + + rows.forEach((v) => { + const time = new Date(v.time); + if (!startTime) { + startTime = time; + } + + endTime = time; + + const dateStr = toPeriodDateString(time, period); + const key = v[segment]; + + keys[key] = true; + + const k = key ? key : 'total'; + const quoteVolume = Math.round(v.quoteVolume * 100) / 100; + + if (dateIndex[dateStr]) { + dateIndex[dateStr][k] = quoteVolume; + } else { + dateIndex[dateStr] = { + date: dateStr, + year: time.getFullYear(), + month: time.getMonth() + 1, + day: time.getDate(), + [k]: quoteVolume, + }; + } + }); + + let data = []; + while (startTime < endTime) { + const dateStr = toPeriodDateString(startTime, period); + const groupData = dateIndex[dateStr]; + if (groupData) { + data.push(groupData); + } else { + data.push({ + date: dateStr, + year: startTime.getFullYear(), + month: startTime.getMonth() + 1, + day: startTime.getDate(), + total: 0, + }); + } + + switch (period) { + case 'day': + startTime.setDate(startTime.getDate() + 1); + break; + case 'month': + startTime.setMonth(startTime.getMonth() + 1); + break; + case 'year': + startTime.setFullYear(startTime.getFullYear() + 1); + break; + } + } + + return [data, Object.keys(keys)]; +} + +export default function TradingVolumeBar(props) { + const [tradingVolumes, setTradingVolumes] = useState([]); + const [period, setPeriod] = useState(props.period); + const [segment, setSegment] = useState(props.segment); + + useEffect(() => { + if (props.period !== period) { + setPeriod(props.period); + } + + if (props.segment !== segment) { + setSegment(props.segment); + } + + queryTradingVolume( + { period: props.period, segment: props.segment }, + (tradingVolumes) => { + setTradingVolumes(tradingVolumes); + } + ); + }, [props.period, props.segment]); + + const [data, keys] = groupData(tradingVolumes, period, segment); + + return ( + + ); +} diff --git a/apps/frontend/components/TradingVolumePanel.js b/apps/frontend/components/TradingVolumePanel.js new file mode 100644 index 0000000..165ebcc --- /dev/null +++ b/apps/frontend/components/TradingVolumePanel.js @@ -0,0 +1,72 @@ +import Paper from '@mui/material/Paper'; +import Box from '@mui/material/Box'; +import Tabs from '@mui/material/Tabs'; +import Tab from '@mui/material/Tab'; +import React from 'react'; +import TradingVolumeBar from './TradingVolumeBar'; +import { makeStyles } from '@mui/styles'; +import Grid from '@mui/material/Grid'; +import Typography from '@mui/material/Typography'; + +const useStyles = makeStyles((theme) => ({ + tradingVolumeBarBox: { + height: 400, + }, + paper: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, +})); + +export default function TradingVolumePanel() { + const [period, setPeriod] = React.useState('day'); + const [segment, setSegment] = React.useState('exchange'); + const classes = useStyles(); + const handlePeriodChange = (event, newValue) => { + setPeriod(newValue); + }; + + const handleSegmentChange = (event, newValue) => { + setSegment(newValue); + }; + + return ( + + + Trading Volume + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/frontend/hooks/useInterval.ts b/apps/frontend/hooks/useInterval.ts new file mode 100644 index 0000000..9a54d77 --- /dev/null +++ b/apps/frontend/hooks/useInterval.ts @@ -0,0 +1,20 @@ +import { useEffect, useRef } from 'react'; + +export default function useInterval(cb: Function, delayMs: number | null) { + const savedCallback = useRef(); + + useEffect(() => { + savedCallback.current = cb; + }, [cb]); + + useEffect(() => { + function tick() { + savedCallback.current(); + } + + if (delayMs !== null) { + let timerId = setInterval(tick, delayMs); + return () => clearInterval(timerId); + } + }, [delayMs]); +} diff --git a/apps/frontend/layouts/DashboardLayout.js b/apps/frontend/layouts/DashboardLayout.js new file mode 100644 index 0000000..1f9ffd8 --- /dev/null +++ b/apps/frontend/layouts/DashboardLayout.js @@ -0,0 +1,65 @@ +import React from 'react'; + +import { makeStyles } from '@mui/styles'; +import AppBar from '@mui/material/AppBar'; +import Toolbar from '@mui/material/Toolbar'; +import Typography from '@mui/material/Typography'; +import Container from '@mui/material/Container'; + +import SideBar from '../components/SideBar'; +import SyncButton from '../components/SyncButton'; + +import ConnectWallet from '../components/ConnectWallet'; +import { Box } from '@mui/material'; + +const useStyles = makeStyles((theme) => ({ + root: { + flexGrow: 1, + display: 'flex', + }, + content: { + flexGrow: 1, + height: '100vh', + overflow: 'auto', + }, + appBar: { + zIndex: theme.zIndex.drawer + 1, + }, + appBarSpacer: theme.mixins.toolbar, + container: {}, + toolbar: { + justifyContent: 'space-between', + }, +})); + +export default function DashboardLayout({ children }) { + const classes = useStyles(); + + return ( +
+ + + + BBGO + + + + + + + + + +
+
+ + {children} + +
+
+ ); +} diff --git a/apps/frontend/layouts/PlainLayout.js b/apps/frontend/layouts/PlainLayout.js new file mode 100644 index 0000000..8bbca9d --- /dev/null +++ b/apps/frontend/layouts/PlainLayout.js @@ -0,0 +1,43 @@ +import React from 'react'; + +import { makeStyles } from '@mui/styles'; +import AppBar from '@mui/material/AppBar'; +import Toolbar from '@mui/material/Toolbar'; +import Typography from '@mui/material/Typography'; +import Container from '@mui/material/Container'; + +const useStyles = makeStyles((theme) => ({ + root: { + // flexGrow: 1, + display: 'flex', + }, + content: { + flexGrow: 1, + height: '100vh', + overflow: 'auto', + }, + appBar: { + zIndex: theme.zIndex.drawer + 1, + }, + appBarSpacer: theme.mixins.toolbar, +})); + +export default function PlainLayout(props) { + const classes = useStyles(); + return ( +
+ + + + {props && props.title ? props.title : 'BBGO Setup Wizard'} + + + + +
+
+ {props.children} +
+
+ ); +} diff --git a/apps/frontend/next-env.d.ts b/apps/frontend/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/apps/frontend/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/apps/frontend/next.config.js b/apps/frontend/next.config.js new file mode 100644 index 0000000..c9fac5d --- /dev/null +++ b/apps/frontend/next.config.js @@ -0,0 +1,9 @@ +module.exports = async (phase, { defaultConfig }) => { + /** + * @type {import('next').NextConfig} + */ + const nextConfig = { + /* config options here */ + } + return nextConfig +} \ No newline at end of file diff --git a/apps/frontend/package.json b/apps/frontend/package.json new file mode 100644 index 0000000..0096838 --- /dev/null +++ b/apps/frontend/package.json @@ -0,0 +1,42 @@ +{ + "name": "frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "yarn run next dev", + "build": "yarn run next build", + "start": "yarn run next start", + "export": "yarn run next build && yarn run next export", + "prettier": "prettier --write ." + }, + "dependencies": { + "@emotion/react": "^11.9.3", + "@emotion/styled": "^11.9.3", + "@ethersproject/units": "^5.6.1", + "@mui/icons-material": "^5.8.3", + "@mui/lab": "^5.0.0-alpha.85", + "@mui/material": "^5.8.3", + "@mui/styles": "^5.8.3", + "@mui/x-data-grid": "^5.12.1", + "@nivo/bar": "^0.79.1", + "@nivo/core": "^0.79.0", + "@nivo/pie": "^0.79.1", + "@usedapp/core": "1.0.9", + "axios": "^0.27.2", + "classnames": "^2.2.6", + "ethers": "^5.6.9", + "isomorphic-fetch": "^3.0.0", + "next": "12", + "qrcode.react": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-number-format": "^4.4.4" + }, + "devDependencies": { + "@types/node": "^18.0.0", + "@types/react": "^18.0.14", + "next-transpile-modules": "^9.0.0", + "prettier": "^2.6.2", + "typescript": "^4.1.3" + } +} diff --git a/apps/frontend/pages/_app.tsx b/apps/frontend/pages/_app.tsx new file mode 100644 index 0000000..78178c8 --- /dev/null +++ b/apps/frontend/pages/_app.tsx @@ -0,0 +1,43 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import Head from 'next/head'; + +import { ThemeProvider } from '@mui/material/styles'; + +import CssBaseline from '@mui/material/CssBaseline'; +import theme from '../src/theme'; +import '../styles/globals.css'; + +export default function MyApp(props) { + const { Component, pageProps } = props; + + useEffect(() => { + // Remove the server-side injected CSS. + const jssStyles = document.querySelector('#jss-server-side'); + if (jssStyles) { + jssStyles.parentElement.removeChild(jssStyles); + } + }, []); + + return ( + + + BBGO + + + + {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} + + + + + ); +} + +MyApp.propTypes = { + Component: PropTypes.elementType.isRequired, + pageProps: PropTypes.object.isRequired, +}; diff --git a/apps/frontend/pages/_document.js b/apps/frontend/pages/_document.js new file mode 100644 index 0000000..72d1a1f --- /dev/null +++ b/apps/frontend/pages/_document.js @@ -0,0 +1,72 @@ +/* eslint-disable react/jsx-filename-extension */ +import React from 'react'; +import Document, { Html, Head, Main, NextScript } from 'next/document'; +import { ServerStyleSheets } from '@mui/styles'; +import theme from '../src/theme'; + +export default class MyDocument extends Document { + render() { + return ( + + + {/* PWA primary color */} + + + + +
+ + + + ); + } +} + +// `getInitialProps` belongs to `_document` (instead of `_app`), +// it's compatible with server-side generation (SSG). +MyDocument.getInitialProps = async (ctx) => { + // Resolution order + // + // On the server: + // 1. app.getInitialProps + // 2. page.getInitialProps + // 3. document.getInitialProps + // 4. app.render + // 5. page.render + // 6. document.render + // + // On the server with error: + // 1. document.getInitialProps + // 2. app.render + // 3. page.render + // 4. document.render + // + // On the client + // 1. app.getInitialProps + // 2. page.getInitialProps + // 3. app.render + // 4. page.render + + // Render app and page and get the context of the page with collected side effects. + const sheets = new ServerStyleSheets(); + const originalRenderPage = ctx.renderPage; + + ctx.renderPage = () => + originalRenderPage({ + enhanceApp: (App) => (props) => sheets.collect(), + }); + + const initialProps = await Document.getInitialProps(ctx); + + return { + ...initialProps, + // Styles fragment is rendered after the app and page rendering finish. + styles: [ + ...React.Children.toArray(initialProps.styles), + sheets.getStyleElement(), + ], + }; +}; diff --git a/apps/frontend/pages/api/hello.js b/apps/frontend/pages/api/hello.js new file mode 100644 index 0000000..07d9d9b --- /dev/null +++ b/apps/frontend/pages/api/hello.js @@ -0,0 +1,6 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction + +export default (req, res) => { + res.statusCode = 200; + res.json({ name: 'John Doe' }); +}; diff --git a/apps/frontend/pages/connect/index.js b/apps/frontend/pages/connect/index.js new file mode 100644 index 0000000..0e2eb47 --- /dev/null +++ b/apps/frontend/pages/connect/index.js @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from 'react'; + +import { makeStyles } from '@mui/styles'; +import Typography from '@mui/material/Typography'; +import Paper from '@mui/material/Paper'; +import PlainLayout from '../../layouts/PlainLayout'; +import { QRCodeSVG } from 'qrcode.react'; +import { queryOutboundIP } from '../../api/bbgo'; + +const useStyles = makeStyles((theme) => ({ + paper: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, + dataGridContainer: { + display: 'flex', + textAlign: 'center', + alignItems: 'center', + alignContent: 'center', + height: 320, + }, +})); + +function fetchConnectUrl(cb) { + return queryOutboundIP((outboundIP) => { + cb( + window.location.protocol + '//' + outboundIP + ':' + window.location.port + ); + }); +} + +export default function Connect() { + const classes = useStyles(); + + const [connectUrl, setConnectUrl] = useState([]); + + useEffect(() => { + fetchConnectUrl(function (url) { + setConnectUrl(url); + }); + }, []); + + return ( + + + + Sign In Using QR Codes + +
+ +
+
+
+ ); +} diff --git a/apps/frontend/pages/index.tsx b/apps/frontend/pages/index.tsx new file mode 100644 index 0000000..3185b81 --- /dev/null +++ b/apps/frontend/pages/index.tsx @@ -0,0 +1,121 @@ +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; + +import { makeStyles } from '@mui/styles'; +import Typography from '@mui/material/Typography'; +import Box from '@mui/material/Box'; +import Grid from '@mui/material/Grid'; +import Paper from '@mui/material/Paper'; + +import TotalAssetsPie from '../components/TotalAssetsPie'; +import TotalAssetSummary from '../components/TotalAssetsSummary'; +import TotalAssetDetails from '../components/TotalAssetsDetails'; + +import TradingVolumePanel from '../components/TradingVolumePanel'; +import ExchangeSessionTabPanel from '../components/ExchangeSessionTabPanel'; + +import DashboardLayout from '../layouts/DashboardLayout'; + +import { queryAssets, querySessions } from '../api/bbgo'; + +import { ChainId, Config, DAppProvider } from '@usedapp/core'; +import { Theme } from '@mui/material/styles'; + +// fix the `theme.spacing` missing error +// https://stackoverflow.com/a/70707121/3897950 +declare module '@mui/styles/defaultTheme' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface (remove this line if you don't have the rule enabled) + interface DefaultTheme extends Theme {} +} + +const useStyles = makeStyles((theme) => ({ + totalAssetsSummary: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, + grid: { + flexGrow: 1, + }, + control: { + padding: theme.spacing(2), + }, +})); + +const config: Config = { + readOnlyChainId: ChainId.Mainnet, + readOnlyUrls: { + [ChainId.Mainnet]: + 'https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161', + }, +}; + +// props are pageProps passed from _app.tsx +export default function Home() { + const classes = useStyles(); + const router = useRouter(); + + const [assets, setAssets] = useState({}); + const [sessions, setSessions] = React.useState([]); + + React.useEffect(() => { + querySessions((sessions) => { + if (sessions && sessions.length > 0) { + setSessions(sessions); + queryAssets(setAssets); + } else { + router.push('/setup'); + } + }).catch((err) => { + console.error(err); + }); + }, [router]); + + if (sessions.length == 0) { + return ( + + + + Loading + + + + ); + } + + console.log('index: assets', assets); + + return ( + + + + + Total Assets + + +
+ + + + + + + + + + +
+
+ + + + +
+
+ ); +} diff --git a/apps/frontend/pages/orders.js b/apps/frontend/pages/orders.js new file mode 100644 index 0000000..744b67e --- /dev/null +++ b/apps/frontend/pages/orders.js @@ -0,0 +1,81 @@ +import React, { useEffect, useState } from 'react'; + +import { makeStyles } from '@mui/styles'; +import Typography from '@mui/material/Typography'; +import Paper from '@mui/material/Paper'; +import { queryClosedOrders } from '../api/bbgo'; +import { DataGrid } from '@mui/x-data-grid'; +import DashboardLayout from '../layouts/DashboardLayout'; + +const columns = [ + { field: 'gid', headerName: 'GID', width: 80, type: 'number' }, + { field: 'clientOrderID', headerName: 'Client Order ID', width: 130 }, + { field: 'exchange', headerName: 'Exchange' }, + { field: 'symbol', headerName: 'Symbol' }, + { field: 'orderType', headerName: 'Type' }, + { field: 'side', headerName: 'Side', width: 90 }, + { + field: 'averagePrice', + headerName: 'Average Price', + type: 'number', + width: 120, + }, + { field: 'quantity', headerName: 'Quantity', type: 'number' }, + { + field: 'executedQuantity', + headerName: 'Executed Quantity', + type: 'number', + }, + { field: 'status', headerName: 'Status' }, + { field: 'isMargin', headerName: 'Margin' }, + { field: 'isIsolated', headerName: 'Isolated' }, + { field: 'creationTime', headerName: 'Create Time', width: 200 }, +]; + +const useStyles = makeStyles((theme) => ({ + paper: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, + dataGridContainer: { + display: 'flex', + height: 'calc(100vh - 64px - 120px)', + }, +})); + +export default function Orders() { + const classes = useStyles(); + + const [orders, setOrders] = useState([]); + + useEffect(() => { + queryClosedOrders({}, (orders) => { + setOrders( + orders.map((o) => { + o.id = o.gid; + return o; + }) + ); + }); + }, []); + + return ( + + + + Orders + +
+
+ +
+
+
+
+ ); +} diff --git a/apps/frontend/pages/setup/index.js b/apps/frontend/pages/setup/index.js new file mode 100644 index 0000000..664e479 --- /dev/null +++ b/apps/frontend/pages/setup/index.js @@ -0,0 +1,132 @@ +import React from 'react'; + +import { makeStyles } from '@mui/styles'; +import Typography from '@mui/material/Typography'; +import Box from '@mui/material/Box'; +import Paper from '@mui/material/Paper'; +import Stepper from '@mui/material/Stepper'; +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; + +import ConfigureDatabaseForm from '../../components/ConfigureDatabaseForm'; +import AddExchangeSessionForm from '../../components/AddExchangeSessionForm'; +import ReviewSessions from '../../components/ReviewSessions'; +import ConfigureGridStrategyForm from '../../components/ConfigureGridStrategyForm'; +import ReviewStrategies from '../../components/ReviewStrategies'; +import SaveConfigAndRestart from '../../components/SaveConfigAndRestart'; + +import PlainLayout from '../../layouts/PlainLayout'; + +const useStyles = makeStyles((theme) => ({ + paper: { + padding: theme.spacing(2), + }, +})); + +const steps = [ + 'Configure Database', + 'Add Exchange Session', + 'Review Sessions', + 'Configure Strategy', + 'Review Strategies', + 'Save Config and Restart', +]; + +function getStepContent(step, setActiveStep) { + switch (step) { + case 0: + return ( + { + setActiveStep(1); + }} + /> + ); + case 1: + return ( + { + setActiveStep(0); + }} + onAdded={() => { + setActiveStep(2); + }} + /> + ); + case 2: + return ( + { + setActiveStep(1); + }} + onNext={() => { + setActiveStep(3); + }} + /> + ); + case 3: + return ( + { + setActiveStep(2); + }} + onAdded={() => { + setActiveStep(4); + }} + /> + ); + case 4: + return ( + { + setActiveStep(3); + }} + onNext={() => { + setActiveStep(5); + }} + /> + ); + + case 5: + return ( + { + setActiveStep(4); + }} + onRestarted={() => {}} + /> + ); + + default: + throw new Error('Unknown step'); + } +} + +export default function Setup() { + const classes = useStyles(); + const [activeStep, setActiveStep] = React.useState(0); + + return ( + + + + + Setup Session + + + + {steps.map((label) => ( + + {label} + + ))} + + + + {getStepContent(activeStep, setActiveStep)} + + + + + ); +} diff --git a/apps/frontend/pages/strategies.tsx b/apps/frontend/pages/strategies.tsx new file mode 100644 index 0000000..1ff03af --- /dev/null +++ b/apps/frontend/pages/strategies.tsx @@ -0,0 +1,43 @@ +import { styled } from '@mui/styles'; +import DashboardLayout from '../layouts/DashboardLayout'; +import { useEffect, useState } from 'react'; +import { queryStrategiesMetrics } from '../api/bbgo'; +import type { GridStrategy } from '../api/bbgo'; + +import Detail from '../components/Detail'; + +const StrategiesContainer = styled('div')(() => ({ + width: '100%', + height: '100%', + padding: '40px 20px', + display: 'grid', + gridTemplateColumns: 'repeat(3, 350px);', + justifyContent: 'center', + gap: '30px', + '@media(max-width: 1400px)': { + gridTemplateColumns: 'repeat(2, 350px)', + }, + '@media(max-width: 1000px)': { + gridTemplateColumns: '350px', + }, +})); + +export default function Strategies() { + const [details, setDetails] = useState([]); + + useEffect(() => { + queryStrategiesMetrics().then((value) => { + setDetails(value); + }); + }, []); + + return ( + + + {details.map((element) => { + return ; + })} + + + ); +} diff --git a/apps/frontend/pages/trades.js b/apps/frontend/pages/trades.js new file mode 100644 index 0000000..d300f95 --- /dev/null +++ b/apps/frontend/pages/trades.js @@ -0,0 +1,68 @@ +import React, { useEffect, useState } from 'react'; + +import { makeStyles } from '@mui/styles'; +import Typography from '@mui/material/Typography'; +import Paper from '@mui/material/Paper'; +import { queryTrades } from '../api/bbgo'; +import { DataGrid } from '@mui/x-data-grid'; +import DashboardLayout from '../layouts/DashboardLayout'; + +const columns = [ + { field: 'gid', headerName: 'GID', width: 80, type: 'number' }, + { field: 'exchange', headerName: 'Exchange' }, + { field: 'symbol', headerName: 'Symbol' }, + { field: 'side', headerName: 'Side', width: 90 }, + { field: 'price', headerName: 'Price', type: 'number', width: 120 }, + { field: 'quantity', headerName: 'Quantity', type: 'number' }, + { field: 'isMargin', headerName: 'Margin' }, + { field: 'isIsolated', headerName: 'Isolated' }, + { field: 'tradedAt', headerName: 'Trade Time', width: 200 }, +]; + +const useStyles = makeStyles((theme) => ({ + paper: { + margin: theme.spacing(2), + padding: theme.spacing(2), + }, + dataGridContainer: { + display: 'flex', + height: 'calc(100vh - 64px - 120px)', + }, +})); + +export default function Trades() { + const classes = useStyles(); + + const [trades, setTrades] = useState([]); + + useEffect(() => { + queryTrades({}, (trades) => { + setTrades( + trades.map((o) => { + o.id = o.gid; + return o; + }) + ); + }); + }, []); + + return ( + + + + Trades + +
+
+ +
+
+
+
+ ); +} diff --git a/apps/frontend/public/favicon.ico b/apps/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a GIT binary patch literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*- + + + + + + + + diff --git a/apps/frontend/public/images/bnb-logo.svg b/apps/frontend/public/images/bnb-logo.svg new file mode 100644 index 0000000..91a66e0 --- /dev/null +++ b/apps/frontend/public/images/bnb-logo.svg @@ -0,0 +1 @@ +bi \ No newline at end of file diff --git a/apps/frontend/public/images/btc-logo.svg b/apps/frontend/public/images/btc-logo.svg new file mode 100644 index 0000000..2b75c99 --- /dev/null +++ b/apps/frontend/public/images/btc-logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/apps/frontend/public/images/comp-logo.svg b/apps/frontend/public/images/comp-logo.svg new file mode 100644 index 0000000..0face3c --- /dev/null +++ b/apps/frontend/public/images/comp-logo.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/apps/frontend/public/images/dai-logo.svg b/apps/frontend/public/images/dai-logo.svg new file mode 100644 index 0000000..2ae2e32 --- /dev/null +++ b/apps/frontend/public/images/dai-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/apps/frontend/public/images/dot-logo.svg b/apps/frontend/public/images/dot-logo.svg new file mode 100644 index 0000000..89d0e71 --- /dev/null +++ b/apps/frontend/public/images/dot-logo.svg @@ -0,0 +1,20 @@ + + + + +polkadot + + + diff --git a/apps/frontend/public/images/eth-logo.svg b/apps/frontend/public/images/eth-logo.svg new file mode 100644 index 0000000..684e968 --- /dev/null +++ b/apps/frontend/public/images/eth-logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/apps/frontend/public/images/grt-logo.svg b/apps/frontend/public/images/grt-logo.svg new file mode 100644 index 0000000..a3db5b7 --- /dev/null +++ b/apps/frontend/public/images/grt-logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/apps/frontend/public/images/link-logo.svg b/apps/frontend/public/images/link-logo.svg new file mode 100644 index 0000000..bf4cd53 --- /dev/null +++ b/apps/frontend/public/images/link-logo.svg @@ -0,0 +1 @@ +Asset 1 \ No newline at end of file diff --git a/apps/frontend/public/images/ltc-logo.svg b/apps/frontend/public/images/ltc-logo.svg new file mode 100644 index 0000000..13e76a4 --- /dev/null +++ b/apps/frontend/public/images/ltc-logo.svg @@ -0,0 +1 @@ +litecoin-ltc-logo \ No newline at end of file diff --git a/apps/frontend/public/images/max-logo.svg b/apps/frontend/public/images/max-logo.svg new file mode 100644 index 0000000..fae1cdf --- /dev/null +++ b/apps/frontend/public/images/max-logo.svg @@ -0,0 +1 @@ + diff --git a/apps/frontend/public/images/snt-logo.svg b/apps/frontend/public/images/snt-logo.svg new file mode 100644 index 0000000..f7bd0b7 --- /dev/null +++ b/apps/frontend/public/images/snt-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/frontend/public/images/sxp-logo.svg b/apps/frontend/public/images/sxp-logo.svg new file mode 100644 index 0000000..27a4983 --- /dev/null +++ b/apps/frontend/public/images/sxp-logo.svg @@ -0,0 +1 @@ +Asset 2 \ No newline at end of file diff --git a/apps/frontend/public/images/twd-logo.svg b/apps/frontend/public/images/twd-logo.svg new file mode 100644 index 0000000..c1515e7 --- /dev/null +++ b/apps/frontend/public/images/twd-logo.svg @@ -0,0 +1 @@ + diff --git a/apps/frontend/public/images/usdt-logo.svg b/apps/frontend/public/images/usdt-logo.svg new file mode 100644 index 0000000..e530822 --- /dev/null +++ b/apps/frontend/public/images/usdt-logo.svg @@ -0,0 +1 @@ +tether-usdt-logo \ No newline at end of file diff --git a/apps/frontend/public/images/xrp-logo.svg b/apps/frontend/public/images/xrp-logo.svg new file mode 100644 index 0000000..9a2c7c6 --- /dev/null +++ b/apps/frontend/public/images/xrp-logo.svg @@ -0,0 +1 @@ +x \ No newline at end of file diff --git a/apps/frontend/public/images/yfi-logo.svg b/apps/frontend/public/images/yfi-logo.svg new file mode 100644 index 0000000..9b4b060 --- /dev/null +++ b/apps/frontend/public/images/yfi-logo.svg @@ -0,0 +1 @@ +yearn-finance-yfi diff --git a/apps/frontend/public/vercel.svg b/apps/frontend/public/vercel.svg new file mode 100644 index 0000000..fbf0e25 --- /dev/null +++ b/apps/frontend/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/apps/frontend/src/theme.js b/apps/frontend/src/theme.js new file mode 100644 index 0000000..ec5e14d --- /dev/null +++ b/apps/frontend/src/theme.js @@ -0,0 +1,24 @@ +import { createTheme } from '@mui/material/styles'; +import { red } from '@mui/material/colors'; + +// Create a theme instance. +const theme = createTheme({ + palette: { + primary: { + main: '#eb9534', + contrastText: '#ffffff', + }, + secondary: { + main: '#ccc0b1', + contrastText: '#eb9534', + }, + error: { + main: red.A400, + }, + background: { + default: '#fff', + }, + }, +}); + +export default theme; diff --git a/apps/frontend/src/utils.js b/apps/frontend/src/utils.js new file mode 100644 index 0000000..54b09ce --- /dev/null +++ b/apps/frontend/src/utils.js @@ -0,0 +1,37 @@ +export function currencyColor(currency) { + switch (currency) { + case 'BTC': + return '#f69c3d'; + case 'ETH': + return '#497493'; + case 'MCO': + return '#032144'; + case 'OMG': + return '#2159ec'; + case 'LTC': + return '#949494'; + case 'USDT': + return '#2ea07b'; + case 'SAND': + return '#2E9AD0'; + case 'XRP': + return '#00AAE4'; + case 'BCH': + return '#8DC351'; + case 'MAX': + return '#2D4692'; + case 'TWD': + return '#4A7DED'; + } +} + +export function throttle(fn, delayMillis) { + let permitted = true; + return () => { + if (permitted) { + fn.apply(this, arguments); + permitted = false; + setTimeout(() => (permitted = true), delayMillis); + } + }; +} diff --git a/apps/frontend/styles/Home.module.css b/apps/frontend/styles/Home.module.css new file mode 100644 index 0000000..42e7e60 --- /dev/null +++ b/apps/frontend/styles/Home.module.css @@ -0,0 +1,122 @@ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + justify-content: center; + align-items: center; +} + +.footer img { + margin-left: 0.5rem; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; + margin-top: 3rem; +} + +.card { + margin: 1rem; + flex-basis: 45%; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h3 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/apps/frontend/styles/globals.css b/apps/frontend/styles/globals.css new file mode 100644 index 0000000..e5e2dcc --- /dev/null +++ b/apps/frontend/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/apps/frontend/tsconfig.json b/apps/frontend/tsconfig.json new file mode 100644 index 0000000..5bee8c4 --- /dev/null +++ b/apps/frontend/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/apps/frontend/yarn.lock b/apps/frontend/yarn.lock new file mode 100644 index 0000000..6ef54bb --- /dev/null +++ b/apps/frontend/yarn.lock @@ -0,0 +1,2240 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.17.10": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" + integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== + +"@babel/core@^7.0.0": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" + integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-compilation-targets" "^7.18.2" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helpers" "^7.18.2" + "@babel/parser" "^7.18.5" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.5" + "@babel/types" "^7.18.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" + integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== + dependencies: + "@babel/types" "^7.18.2" + "@jridgewell/gen-mapping" "^0.3.0" + jsesc "^2.5.1" + +"@babel/generator@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" + integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== + dependencies: + "@babel/compat-data" "^7.17.10" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" + integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" + integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.0" + "@babel/types" "^7.18.0" + +"@babel/helper-plugin-utils@^7.17.12": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" + integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== + +"@babel/helper-simple-access@^7.17.7": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" + integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== + dependencies: + "@babel/types" "^7.18.2" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" + integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" + +"@babel/highlight@^7.16.7": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" + integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.16.7", "@babel/parser@^7.18.5": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" + integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== + +"@babel/parser@^7.22.15", "@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/plugin-syntax-jsx@^7.12.13": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" + integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== + dependencies: + "@babel/helper-plugin-utils" "^7.17.12" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": + version "7.18.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5" + integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.16.7", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@date-io/core@^2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.14.0.tgz#03e9b9b9fc8e4d561c32dd324df0f3ccd967ef14" + integrity sha512-qFN64hiFjmlDHJhu+9xMkdfDG2jLsggNxKXglnekUpXSq8faiqZgtHm2lsHCUuaPDTV6wuXHcCl8J1GQ5wLmPw== + +"@date-io/date-fns@^2.11.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.14.0.tgz#92ab150f488f294c135c873350d154803cebdbea" + integrity sha512-4fJctdVyOd5cKIKGaWUM+s3MUXMuzkZaHuTY15PH70kU1YTMrCoauA7hgQVx9qj0ZEbGrH9VSPYJYnYro7nKiA== + dependencies: + "@date-io/core" "^2.14.0" + +"@date-io/dayjs@^2.11.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@date-io/dayjs/-/dayjs-2.14.0.tgz#8d4e93e1d473bb5f25210866204dc33384ca4c20" + integrity sha512-4fRvNWaOh7AjvOyJ4h6FYMS7VHLQnIEeAV5ahv6sKYWx+1g1UwYup8h7+gPuoF+sW2hTScxi7PVaba2Jk/U8Og== + dependencies: + "@date-io/core" "^2.14.0" + +"@date-io/luxon@^2.11.1": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@date-io/luxon/-/luxon-2.14.0.tgz#cd1641229e00a899625895de3a31e3aaaf66629f" + integrity sha512-KmpBKkQFJ/YwZgVd0T3h+br/O0uL9ZdE7mn903VPAG2ZZncEmaUfUdYKFT7v7GyIKJ4KzCp379CRthEbxevEVg== + dependencies: + "@date-io/core" "^2.14.0" + +"@date-io/moment@^2.11.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@date-io/moment/-/moment-2.14.0.tgz#8300abd6ae8c55d8edee90d118db3cef0b1d4f58" + integrity sha512-VsoLXs94GsZ49ecWuvFbsa081zEv2xxG7d+izJsqGa2L8RPZLlwk27ANh87+SNnOUpp+qy2AoCAf0mx4XXhioA== + dependencies: + "@date-io/core" "^2.14.0" + +"@emotion/babel-plugin@^11.7.1": + version "11.9.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95" + integrity sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + +"@emotion/cache@^11.7.1", "@emotion/cache@^11.9.3": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.9.3.tgz#96638449f6929fd18062cfe04d79b29b44c0d6cb" + integrity sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.1" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + +"@emotion/is-prop-valid@^1.1.2", "@emotion/is-prop-valid@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.3.tgz#f0907a416368cf8df9e410117068e20fe87c0a3a" + integrity sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA== + dependencies: + "@emotion/memoize" "^0.7.4" + +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.9.3": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.3.tgz#f4f4f34444f6654a2e550f5dab4f2d360c101df9" + integrity sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.9.3" + "@emotion/serialize" "^1.0.4" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.0.2", "@emotion/serialize@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.4.tgz#ff31fd11bb07999611199c2229e152faadc21a3c" + integrity sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.1.tgz#015756e2a9a3c7c5f11d8ec22966a8dbfbfac787" + integrity sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA== + +"@emotion/styled@^11.9.3": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.9.3.tgz#47f0c71137fec7c57035bf3659b52fb536792340" + integrity sha512-o3sBNwbtoVz9v7WB1/Y/AmXl69YHmei2mrVnK7JgyBJ//Rst5yqPZCecEJlMlJrFeWHp+ki/54uN265V2pEcXA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/is-prop-valid" "^1.1.3" + "@emotion/serialize" "^1.0.4" + "@emotion/utils" "^1.1.0" + +"@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" + integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== + +"@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + +"@ethersproject/abi@5.6.4", "@ethersproject/abi@^5.6.3": + version "5.6.4" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" + integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== + dependencies: + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/abstract-provider@5.6.1", "@ethersproject/abstract-provider@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz#02ddce150785caf0c77fe036a0ebfcee61878c59" + integrity sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.3" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/web" "^5.6.1" + +"@ethersproject/abstract-signer@5.6.2", "@ethersproject/abstract-signer@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz#491f07fc2cbd5da258f46ec539664713950b0b33" + integrity sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + +"@ethersproject/address@5.6.1", "@ethersproject/address@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" + integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + +"@ethersproject/base64@5.6.1", "@ethersproject/base64@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.1.tgz#2c40d8a0310c9d1606c2c37ae3092634b41d87cb" + integrity sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + +"@ethersproject/basex@5.6.1", "@ethersproject/basex@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" + integrity sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + +"@ethersproject/bignumber@5.6.2", "@ethersproject/bignumber@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" + integrity sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.6.1", "@ethersproject/bytes@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" + integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/constants@5.6.1", "@ethersproject/constants@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.1.tgz#e2e974cac160dd101cf79fdf879d7d18e8cb1370" + integrity sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + +"@ethersproject/contracts@5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" + integrity sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.2" + +"@ethersproject/hash@5.6.1", "@ethersproject/hash@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" + integrity sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/hdnode@5.6.2", "@ethersproject/hdnode@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" + integrity sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + +"@ethersproject/json-wallets@5.6.1", "@ethersproject/json-wallets@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" + integrity sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.6.1", "@ethersproject/keccak256@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.1.tgz#b867167c9b50ba1b1a92bccdd4f2d6bd168a91cc" + integrity sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.6.0", "@ethersproject/logger@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" + integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== + +"@ethersproject/networks@5.6.4", "@ethersproject/networks@^5.6.3": + version "5.6.4" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.4.tgz#51296d8fec59e9627554f5a8a9c7791248c8dc07" + integrity sha512-KShHeHPahHI2UlWdtDMn2lJETcbtaJge4k7XSjDR9h79QTd6yQJmv6Cp2ZA4JdqWnhszAOLSuJEd9C0PRw7hSQ== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/pbkdf2@5.6.1", "@ethersproject/pbkdf2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" + integrity sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + +"@ethersproject/properties@5.6.0", "@ethersproject/properties@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" + integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/providers@5.6.8": + version "5.6.8" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" + integrity sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/base64" "^5.6.1" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.3" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/rlp" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/web" "^5.6.1" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.6.1", "@ethersproject/random@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" + integrity sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/rlp@5.6.1", "@ethersproject/rlp@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" + integrity sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/sha2@5.6.1", "@ethersproject/sha2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" + integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.6.2", "@ethersproject/signing-key@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" + integrity sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.1.tgz#5845e71182c66d32e6ec5eefd041fca091a473e2" + integrity sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/strings@5.6.1", "@ethersproject/strings@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.1.tgz#dbc1b7f901db822b5cafd4ebf01ca93c373f8952" + integrity sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/transactions@5.6.2", "@ethersproject/transactions@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.2.tgz#793a774c01ced9fe7073985bb95a4b4e57a6370b" + integrity sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q== + dependencies: + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + +"@ethersproject/units@5.6.1", "@ethersproject/units@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" + integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/wallet@5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" + integrity sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/json-wallets" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + +"@ethersproject/web@5.6.1", "@ethersproject/web@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" + integrity sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA== + dependencies: + "@ethersproject/base64" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/wordlists@5.6.1", "@ethersproject/wordlists@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" + integrity sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" + integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" + integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" + integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.13" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" + integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== + +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" + integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@metamask/detect-provider@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metamask/detect-provider/-/detect-provider-1.2.0.tgz#3667a7531f2a682e3c3a43eaf3a1958bdb42a696" + integrity sha512-ocA76vt+8D0thgXZ7LxFPyqw3H7988qblgzddTDA6B8a/yU0uKV42QR/DhA+Jh11rJjxW0jKvwb5htA6krNZDQ== + +"@mui/base@5.0.0-alpha.85": + version "5.0.0-alpha.85" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.85.tgz#e9e19678bf72dae228d0f25d33dfe20462aac833" + integrity sha512-ONlQJOmQrxmR+pYF9AqH69FOG4ofwzVzNltwb2xKAQIW3VbsNZahcHIpzhFd70W6EIU+QHzB9TzamSM+Fg/U7w== + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/is-prop-valid" "^1.1.2" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + "@popperjs/core" "^2.11.5" + clsx "^1.1.1" + prop-types "^15.8.1" + react-is "^17.0.2" + +"@mui/icons-material@^5.8.3": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.8.4.tgz#3f2907c9f8f5ce4d754cb8fb4b68b5a1abf4d095" + integrity sha512-9Z/vyj2szvEhGWDvb+gG875bOGm8b8rlHBKOD1+nA3PcgC3fV6W1AU6pfOorPeBfH2X4mb9Boe97vHvaSndQvA== + dependencies: + "@babel/runtime" "^7.17.2" + +"@mui/lab@^5.0.0-alpha.85": + version "5.0.0-alpha.86" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.86.tgz#83323e0ff17fdea641fa1d93be024413bf407ec3" + integrity sha512-5dx9/vHldiE5KFu99YUtEGKyUgwTiq8wM+IhEnNKkU+YjEMULVYV+mgS9nvnf6laKtgqy2hOE4JivqRPIuOGdA== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/base" "5.0.0-alpha.85" + "@mui/system" "^5.8.4" + "@mui/utils" "^5.8.4" + "@mui/x-date-pickers" "5.0.0-alpha.1" + clsx "^1.1.1" + prop-types "^15.8.1" + react-is "^17.0.2" + react-transition-group "^4.4.2" + rifm "^0.12.1" + +"@mui/material@^5.8.3": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.8.4.tgz#b9cdae0c79ea770bc9cc3aafb7f750ed8ebe1b5d" + integrity sha512-KlOJS1JGhwuhdoF4fulmz41h/YxyMdZSc+ncz+HAah0GKn8ovAs5774f1w0lIasxbtI1Ziunwvmnu9PvvUKdMw== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/base" "5.0.0-alpha.85" + "@mui/system" "^5.8.4" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + "@types/react-transition-group" "^4.4.4" + clsx "^1.1.1" + csstype "^3.1.0" + prop-types "^15.8.1" + react-is "^17.0.2" + react-transition-group "^4.4.2" + +"@mui/private-theming@^5.8.4": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.8.4.tgz#8ff896601cf84eb9f8394db7674ee4dd2a3343f7" + integrity sha512-3Lp0VAEjtQygJ70MWEyHkKvg327O6YoBH6ZNEy6fIsrK6gmRIj+YrlvJ7LQCbowY+qDGnbdMrTBd1hfThlI8lg== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/utils" "^5.8.4" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.8.0.tgz#89ed42efe7c8749e5a60af035bc5d3a6bea362bf" + integrity sha512-Q3spibB8/EgeMYHc+/o3RRTnAYkSl7ROCLhXJ830W8HZ2/iDiyYp16UcxKPurkXvLhUaILyofPVrP3Su2uKsAw== + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/cache" "^11.7.1" + prop-types "^15.8.1" + +"@mui/styles@^5.8.3": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.8.4.tgz#cc6463df91ad1cc1c035229526f865093bbfc03e" + integrity sha512-Td7dafJDgpdzObT0z5CH/ihOh22MG2vZ7p2tpnrKaq3We50f8l3T69XeTNcy2OH0TWnXJJuASZS/0uMJmVPfag== + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/hash" "^0.8.0" + "@mui/private-theming" "^5.8.4" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + clsx "^1.1.1" + csstype "^3.1.0" + hoist-non-react-statics "^3.3.2" + jss "^10.8.2" + jss-plugin-camel-case "^10.8.2" + jss-plugin-default-unit "^10.8.2" + jss-plugin-global "^10.8.2" + jss-plugin-nested "^10.8.2" + jss-plugin-props-sort "^10.8.2" + jss-plugin-rule-value-function "^10.8.2" + jss-plugin-vendor-prefixer "^10.8.2" + prop-types "^15.8.1" + +"@mui/system@^5.8.4": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.8.4.tgz#88306aefcc3a60528f69dcd2d66516831859c328" + integrity sha512-eeYZXlOn4p+tYwqqDlci6wW4knJ68aGx5A24YU9ubYZ5o0IwveoNP3LC9sHAMxigk/mUTqL4bpSMJ2HbTn2aQg== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/private-theming" "^5.8.4" + "@mui/styled-engine" "^5.8.0" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + clsx "^1.1.1" + csstype "^3.1.0" + prop-types "^15.8.1" + +"@mui/types@^7.1.4": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.4.tgz#4185c05d6df63ec673cda15feab80440abadc764" + integrity sha512-uveM3byMbthO+6tXZ1n2zm0W3uJCQYtwt/v5zV5I77v2v18u0ITkb8xwhsDD2i3V2Kye7SaNR6FFJ6lMuY/WqQ== + +"@mui/utils@^5.4.1", "@mui/utils@^5.6.0", "@mui/utils@^5.8.4": + version "5.8.4" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.8.4.tgz#5c46b5900bd2452b3ce54a7a1c94a3e2a8a75c34" + integrity sha512-BHYErfrjqqh76KaDAm8wZlhEip1Uj7Cmco65NcsF3BWrAl3FWngACpaPZeEbTgmaEwyWAQEE6LZhsmy43hfyqQ== + dependencies: + "@babel/runtime" "^7.17.2" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^17.0.2" + +"@mui/x-data-grid@^5.12.1": + version "5.12.2" + resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-5.12.2.tgz#e7bde75549ab592ebdafe2d12a2b7f671d484d22" + integrity sha512-OA5jjSoGPrO742GWNSxUPac6U1m8wF0rzcmqlj5vMuBySkPi0ycPRRlVAlYJWTVhSBPs+UWoHA9QpTE19eMBYg== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/utils" "^5.4.1" + clsx "^1.1.1" + prop-types "^15.8.1" + reselect "^4.1.5" + +"@mui/x-date-pickers@5.0.0-alpha.1": + version "5.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-5.0.0-alpha.1.tgz#7450b5544b9ed655db41891c74e2c5f652fbedb7" + integrity sha512-dLPkRiIn2Gr0momblxiOnIwrxn4SijVix+8e08mwAGWhiWcmWep1O9XTRDpZsjB0kjHYCf+kZjlRX4dxnj2acg== + dependencies: + "@date-io/date-fns" "^2.11.0" + "@date-io/dayjs" "^2.11.0" + "@date-io/luxon" "^2.11.1" + "@date-io/moment" "^2.11.0" + "@mui/utils" "^5.6.0" + clsx "^1.1.1" + prop-types "^15.7.2" + react-transition-group "^4.4.2" + rifm "^0.12.1" + +"@next/env@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.6.tgz#5f44823a78335355f00f1687cfc4f1dafa3eca08" + integrity sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA== + +"@next/swc-android-arm-eabi@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz#79a35349b98f2f8c038ab6261aa9cd0d121c03f9" + integrity sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ== + +"@next/swc-android-arm64@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz#ec08ea61794f8752c8ebcacbed0aafc5b9407456" + integrity sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew== + +"@next/swc-darwin-arm64@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz#d1053805615fd0706e9b1667893a72271cd87119" + integrity sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw== + +"@next/swc-darwin-x64@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz#2d1b926a22f4c5230d5b311f9c56cfdcc406afec" + integrity sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg== + +"@next/swc-linux-arm-gnueabihf@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz#c021918d2a94a17f823106a5e069335b8a19724f" + integrity sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw== + +"@next/swc-linux-arm64-gnu@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz#ac55c07bfabde378dfa0ce2b8fc1c3b2897e81ae" + integrity sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ== + +"@next/swc-linux-arm64-musl@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz#e429f826279894be9096be6bec13e75e3d6bd671" + integrity sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ== + +"@next/swc-linux-x64-gnu@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz#1f276c0784a5ca599bfa34b2fcc0b38f3a738e08" + integrity sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ== + +"@next/swc-linux-x64-musl@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz#1d9933dd6ba303dcfd8a2acd6ac7c27ed41e2eea" + integrity sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag== + +"@next/swc-win32-arm64-msvc@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz#2ef9837f12ca652b1783d72ecb86208906042f02" + integrity sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g== + +"@next/swc-win32-ia32-msvc@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz#74003d0aa1c59dfa56cb15481a5c607cbc0027b9" + integrity sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA== + +"@next/swc-win32-x64-msvc@12.1.6": + version "12.1.6" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz#a350caf42975e7197b24b495b8d764eec7e6a36e" + integrity sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA== + +"@nivo/annotations@0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.79.1.tgz#c1b93a1facf55e3f32e2af1b8fb0ba1bebc01910" + integrity sha512-lYso9Luu0maSDtIufwvyVt2+Wue7R9Fh3CIjuRDmNR72UjAgAVEcCar27Fy865UXGsj2hRJZ7KY/1s6kT3gu/w== + dependencies: + "@nivo/colors" "0.79.1" + "@react-spring/web" "9.3.1" + lodash "^4.17.21" + +"@nivo/arcs@0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/arcs/-/arcs-0.79.1.tgz#768d5e91356e94199377fbd0ca762bc364353414" + integrity sha512-owScoElMv5EwDbZKJhns282MnXVM4rq9jYwBnFBx872Igi2r6HwKk1m4jDWGfDktJ7MyECvuVzxRaUImWQdufA== + dependencies: + "@nivo/colors" "0.79.1" + "@react-spring/web" "9.3.1" + d3-shape "^1.3.5" + +"@nivo/axes@0.79.0": + version "0.79.0" + resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.79.0.tgz#6f009819b26f93a4126697152aeab5f979f1ab6c" + integrity sha512-EhSeCPxtWEuxqnifeyF/pIJEzL7pRM3rfygL+MpfT5ypu5NcXYRGQo/Bw0Vh+GF1ML+tNAE0rRvCu2jgLSdVNQ== + dependencies: + "@nivo/scales" "0.79.0" + "@react-spring/web" "9.3.1" + d3-format "^1.4.4" + d3-time-format "^3.0.0" + +"@nivo/bar@^0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/bar/-/bar-0.79.1.tgz#42d28169307e735cb84e57b4b6915195ef1c97fb" + integrity sha512-swJ2FtFeRPWJK9O6aZiqTDi2J6GrU2Z6kIHBBCXBlFmq6+vfd5AqOHytdXPTaN80JsKDBBdtY7tqRjpRPlDZwQ== + dependencies: + "@nivo/annotations" "0.79.1" + "@nivo/axes" "0.79.0" + "@nivo/colors" "0.79.1" + "@nivo/legends" "0.79.1" + "@nivo/scales" "0.79.0" + "@nivo/tooltip" "0.79.0" + "@react-spring/web" "9.3.1" + d3-scale "^3.2.3" + d3-shape "^1.2.2" + lodash "^4.17.21" + +"@nivo/colors@0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.79.1.tgz#0504c08b6a598bc5cb5a8b823d332a73fdc6ef43" + integrity sha512-45huBmz46OoQtfqzHrnqDJ9msebOBX84fTijyOBi8mn8iTDOK2xWgzT7cCYP3hKE58IclkibkzVyWCeJ+rUlqg== + dependencies: + d3-color "^2.0.0" + d3-scale "^3.2.3" + d3-scale-chromatic "^2.0.0" + lodash "^4.17.21" + +"@nivo/core@^0.79.0": + version "0.79.0" + resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.79.0.tgz#5755212c2058c20899990e7c8ec0e918ac00e5f5" + integrity sha512-e1iGodmGuXkF+QWAjhHVFc+lUnfBoUwaWqVcBXBfebzNc50tTJrTTMHyQczjgOIfTc8gEu23lAY4mVZCDKscig== + dependencies: + "@nivo/recompose" "0.79.0" + "@react-spring/web" "9.3.1" + d3-color "^2.0.0" + d3-format "^1.4.4" + d3-interpolate "^2.0.1" + d3-scale "^3.2.3" + d3-scale-chromatic "^2.0.0" + d3-shape "^1.3.5" + d3-time-format "^3.0.0" + lodash "^4.17.21" + +"@nivo/legends@0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.79.1.tgz#60b1806bba547f796e6e5b66943d65153de60c79" + integrity sha512-AoabiLherOAk3/HR/N791fONxNdwNk/gCTJC/6BKUo2nX+JngEYm3nVFmTC1R6RdjwJTeCb9Vtuc4MHA+mcgig== + +"@nivo/pie@^0.79.1": + version "0.79.1" + resolved "https://registry.yarnpkg.com/@nivo/pie/-/pie-0.79.1.tgz#4461e5273adabd0ef52bfcb54fbf6604f676d5a5" + integrity sha512-Cm8I6/nrmcpJLwziUhZ3TtwRV6K/7qWJ6alN6bUh8z7w2nScSnD/PhmAPS89p3jzSUEBPOvCViKwdvyThJ8KCg== + dependencies: + "@nivo/arcs" "0.79.1" + "@nivo/colors" "0.79.1" + "@nivo/legends" "0.79.1" + "@nivo/tooltip" "0.79.0" + d3-shape "^1.3.5" + +"@nivo/recompose@0.79.0": + version "0.79.0" + resolved "https://registry.yarnpkg.com/@nivo/recompose/-/recompose-0.79.0.tgz#c0c54ecabb2300ce672f3c3199f74629df33cc08" + integrity sha512-2GFnOHfA2jzTOA5mdKMwJ6myCRGoXQQbQvFFQ7B/+hnHfU/yrOVpiGt6TPAn3qReC4dyDYrzy1hr9UeQh677ig== + dependencies: + react-lifecycles-compat "^3.0.4" + +"@nivo/scales@0.79.0": + version "0.79.0" + resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.79.0.tgz#553b6910288080fbfbbe4d2aab1dd80e2d172e6e" + integrity sha512-5fAt5Wejp8yzAk6qmA3KU+celCxNYrrBhfvOi2ECDG8KQi+orbDnrO6qjVF6+ebfOn9az8ZVukcSeGA5HceiMg== + dependencies: + d3-scale "^3.2.3" + d3-time "^1.0.11" + d3-time-format "^3.0.0" + lodash "^4.17.21" + +"@nivo/tooltip@0.79.0": + version "0.79.0" + resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.79.0.tgz#3d46be8734e5d30e5387515db0c83bd1c795f442" + integrity sha512-hsJsvhDVR9P/QqIEDIttaA6aslR3tU9So1s/k2jMdppL7J9ZH/IrVx9TbIP7jDKmnU5AMIP5uSstXj9JiKLhQA== + dependencies: + "@react-spring/web" "9.3.1" + +"@popperjs/core@^2.11.5": + version "2.11.5" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" + integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== + +"@react-spring/animated@~9.3.0": + version "9.3.2" + resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.3.2.tgz#bda85e92e9e9b6861c259f2dacb54270a37b0f39" + integrity sha512-pBvKydRHbTzuyaeHtxGIOvnskZxGo/S5/YK1rtYm88b9NQZuZa95Rgd3O0muFL+99nvBMBL8cvQGD0UJmsqQsg== + dependencies: + "@react-spring/shared" "~9.3.0" + "@react-spring/types" "~9.3.0" + +"@react-spring/core@~9.3.0": + version "9.3.2" + resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.3.2.tgz#d1dc5810666ac18550db89c58567f28fbe04fb07" + integrity sha512-kMRjkgdQ6LJ0lmb/wQlONpghaMT83UxglXHJC6m9kZS/GKVmN//TYMEK85xN1rC5Gg+BmjG61DtLCSkkLDTfNw== + dependencies: + "@react-spring/animated" "~9.3.0" + "@react-spring/shared" "~9.3.0" + "@react-spring/types" "~9.3.0" + +"@react-spring/rafz@~9.3.0": + version "9.3.2" + resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.3.2.tgz#0cbd296cd17bbf1e7e49d3b3616884e026d5fb67" + integrity sha512-YtqNnAYp5bl6NdnDOD5TcYS40VJmB+Civ4LPtcWuRPKDAOa/XAf3nep48r0wPTmkK936mpX8aIm7h+luW59u5A== + +"@react-spring/shared@~9.3.0": + version "9.3.2" + resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.3.2.tgz#967ce1d8a16d820a99e6eeb2a8f7ca9311d9dfa0" + integrity sha512-ypGQQ8w7mWnrELLon4h6mBCBxdd8j1pgLzmHXLpTC/f4ya2wdP+0WIKBWXJymIf+5NiTsXgSJra5SnHP5FBY+A== + dependencies: + "@react-spring/rafz" "~9.3.0" + "@react-spring/types" "~9.3.0" + +"@react-spring/types@~9.3.0": + version "9.3.2" + resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.3.2.tgz#0277d436e50d7a824897dd7bb880f4842fbcd0fe" + integrity sha512-u+IK9z9Re4hjNkBYKebZr7xVDYTai2RNBsI4UPL/k0B6lCNSwuqWIXfKZUDVlMOeZHtDqayJn4xz6HcSkTj3FQ== + +"@react-spring/web@9.3.1": + version "9.3.1" + resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.3.1.tgz#5b377ba7ad52e746c2b59e2738c021de3f219d0b" + integrity sha512-sisZIgFGva/Z+xKWPSfXpukF0AP3kR9ALTxlHL87fVotMUCJX5vtH/YlVcywToEFwTHKt3MpI5Wy2M+vgVEeaw== + dependencies: + "@react-spring/animated" "~9.3.0" + "@react-spring/core" "~9.3.0" + "@react-spring/shared" "~9.3.0" + "@react-spring/types" "~9.3.0" + +"@types/node@^18.0.0": + version "18.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" + integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*", "@types/prop-types@^15.7.5": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/react-is@^16.7.1 || ^17.0.0": + version "17.0.3" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a" + integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw== + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.4": + version "4.4.4" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" + integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.14": + version "18.0.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.14.tgz#e016616ffff51dba01b04945610fe3671fdbe06d" + integrity sha512-x4gGuASSiWmo0xjDLpm5mPb52syZHJx02VKbqUKdLmKtAwIh63XClGsiTI1K6DO5q7ox4xAsQrU+Gl3+gGXF9Q== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@uniswap/token-lists@^1.0.0-beta.27": + version "1.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@uniswap/token-lists/-/token-lists-1.0.0-beta.30.tgz#2103ca23b8007c59ec71718d34cdc97861c409e5" + integrity sha512-HwY2VvkQ8lNR6ks5NqQfAtg+4IZqz3KV1T8d2DlI8emIn9uMmaoFbIOg0nzjqAVKKnZSbMTRRtUoAh6mmjRvog== + +"@usedapp/core@1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@usedapp/core/-/core-1.0.9.tgz#f0f08d75be420d9377b3853a4aa99b4e99761cc3" + integrity sha512-vGugFfm55R99mwuJXh1enpiOgDSWOZ2akZ8E2nFJhXzqK6WlTkP7zZuKatlde10X7dLbVC2FTCx3ZhrtLWilIA== + dependencies: + "@metamask/detect-provider" "^1.2.0" + "@uniswap/token-lists" "^1.0.0-beta.27" + fetch-mock "^9.11.0" + lodash.merge "^4.6.2" + lodash.pickby "^4.6.0" + nanoid "3.1.22" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +babel-plugin-macros@^2.6.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserslist@^4.20.2: + version "4.20.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" + integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== + dependencies: + caniuse-lite "^1.0.30001349" + electron-to-chromium "^1.4.147" + escalade "^3.1.1" + node-releases "^2.0.5" + picocolors "^1.0.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001349: + version "1.0.30001357" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001357.tgz#dec7fc4158ef6ad24690d0eec7b91f32b8cb1b5d" + integrity sha512-b+KbWHdHePp+ZpNj+RDHFChZmuN+J5EvuQUlee9jOQIUAdhv9uvAZeEtUeLAknXbkiu1uxjQ9NLp1ie894CuWg== + +chalk@^2.0.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +classnames@^2.2.6: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +convert-source-map@^1.5.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +core-js@^3.0.0: + version "3.23.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.2.tgz#e07a60ca8b14dd129cabdc3d2551baf5a01c76f0" + integrity sha512-ELJOWxNrJfOH/WK4VJ3Qd+fOqZuOuDNDJz0xG6Bt4mGg2eO/UT9CljCrbqDGovjLKUrGajEEBcoTOc0w+yBYeQ== + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +css-vendor@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" + integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== + dependencies: + "@babel/runtime" "^7.8.3" + is-in-browser "^1.0.2" + +csstype@^3.0.2, csstype@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" + integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== + +d3-array@2, d3-array@^2.3.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" + integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + dependencies: + internmap "^1.0.0" + +"d3-color@1 - 2", d3-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" + integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + +"d3-format@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" + integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== + +d3-format@^1.4.4: + version "1.4.5" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" + integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== + +"d3-interpolate@1 - 2", "d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" + integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + dependencies: + d3-color "1 - 2" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +d3-scale-chromatic@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz#c13f3af86685ff91323dc2f0ebd2dabbd72d8bab" + integrity sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA== + dependencies: + d3-color "1 - 2" + d3-interpolate "1 - 2" + +d3-scale@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" + integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== + dependencies: + d3-array "^2.3.0" + d3-format "1 - 2" + d3-interpolate "1.2.0 - 2" + d3-time "^2.1.1" + d3-time-format "2 - 3" + +d3-shape@^1.2.2, d3-shape@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +"d3-time-format@2 - 3", d3-time-format@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" + integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== + dependencies: + d3-time "1 - 2" + +"d3-time@1 - 2", d3-time@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" + integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== + dependencies: + d3-array "2" + +d3-time@^1.0.11: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" + integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +electron-to-chromium@^1.4.147: + version "1.4.162" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.162.tgz#69f8b900477208544a6e2a6e9bd3dc9e73163ed8" + integrity sha512-JrMk3tR2rnBojfAipp9nGh/vcWyBHeNsAVBqehtk4vq0o1bE4sVw19ICeidNx3u0i2yg4X8BvyUIM/yo2vO9aA== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +enhanced-resolve@^5.7.0: + version "5.9.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" + integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +ethers@^5.6.9: + version "5.6.9" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.6.9.tgz#4e12f8dfcb67b88ae7a78a9519b384c23c576a4d" + integrity sha512-lMGC2zv9HC5EC+8r429WaWu3uWJUCgUCt8xxKCFqkrFuBDZXDYIdzDUECxzjf2BMF8IVBByY1EBoGSL3RTm8RA== + dependencies: + "@ethersproject/abi" "5.6.4" + "@ethersproject/abstract-provider" "5.6.1" + "@ethersproject/abstract-signer" "5.6.2" + "@ethersproject/address" "5.6.1" + "@ethersproject/base64" "5.6.1" + "@ethersproject/basex" "5.6.1" + "@ethersproject/bignumber" "5.6.2" + "@ethersproject/bytes" "5.6.1" + "@ethersproject/constants" "5.6.1" + "@ethersproject/contracts" "5.6.2" + "@ethersproject/hash" "5.6.1" + "@ethersproject/hdnode" "5.6.2" + "@ethersproject/json-wallets" "5.6.1" + "@ethersproject/keccak256" "5.6.1" + "@ethersproject/logger" "5.6.0" + "@ethersproject/networks" "5.6.4" + "@ethersproject/pbkdf2" "5.6.1" + "@ethersproject/properties" "5.6.0" + "@ethersproject/providers" "5.6.8" + "@ethersproject/random" "5.6.1" + "@ethersproject/rlp" "5.6.1" + "@ethersproject/sha2" "5.6.1" + "@ethersproject/signing-key" "5.6.2" + "@ethersproject/solidity" "5.6.1" + "@ethersproject/strings" "5.6.1" + "@ethersproject/transactions" "5.6.2" + "@ethersproject/units" "5.6.1" + "@ethersproject/wallet" "5.6.2" + "@ethersproject/web" "5.6.1" + "@ethersproject/wordlists" "5.6.1" + +fetch-mock@^9.11.0: + version "9.11.0" + resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-9.11.0.tgz#371c6fb7d45584d2ae4a18ee6824e7ad4b637a3f" + integrity sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q== + dependencies: + "@babel/core" "^7.0.0" + "@babel/runtime" "^7.0.0" + core-js "^3.0.0" + debug "^4.1.1" + glob-to-regexp "^0.4.0" + is-subset "^0.1.1" + lodash.isequal "^4.5.0" + path-to-regexp "^2.2.1" + querystring "^0.2.0" + whatwg-url "^6.5.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +follow-redirects@^1.14.9: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +glob-to-regexp@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.2.4: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hyphenate-style-name@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" + integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== + +import-fresh@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internmap@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" + integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-in-browser@^1.0.2, is-in-browser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" + integrity sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g== + +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + integrity sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw== + +isomorphic-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +jss-plugin-camel-case@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.9.0.tgz#4921b568b38d893f39736ee8c4c5f1c64670aaf7" + integrity sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww== + dependencies: + "@babel/runtime" "^7.3.1" + hyphenate-style-name "^1.0.3" + jss "10.9.0" + +jss-plugin-default-unit@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.9.0.tgz#bb23a48f075bc0ce852b4b4d3f7582bc002df991" + integrity sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.9.0" + +jss-plugin-global@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.9.0.tgz#fc07a0086ac97aca174e37edb480b69277f3931f" + integrity sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.9.0" + +jss-plugin-nested@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.9.0.tgz#cc1c7d63ad542c3ccc6e2c66c8328c6b6b00f4b3" + integrity sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.9.0" + tiny-warning "^1.0.2" + +jss-plugin-props-sort@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.9.0.tgz#30e9567ef9479043feb6e5e59db09b4de687c47d" + integrity sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.9.0" + +jss-plugin-rule-value-function@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.9.0.tgz#379fd2732c0746fe45168011fe25544c1a295d67" + integrity sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.9.0" + tiny-warning "^1.0.2" + +jss-plugin-vendor-prefixer@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.9.0.tgz#aa9df98abfb3f75f7ed59a3ec50a5452461a206a" + integrity sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA== + dependencies: + "@babel/runtime" "^7.3.1" + css-vendor "^2.0.8" + jss "10.9.0" + +jss@10.9.0, jss@^10.8.2: + version "10.9.0" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.9.0.tgz#7583ee2cdc904a83c872ba695d1baab4b59c141b" + integrity sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw== + dependencies: + "@babel/runtime" "^7.3.1" + csstype "^3.0.2" + is-in-browser "^1.1.3" + tiny-warning "^1.0.2" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + integrity sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@3.1.22: + version "3.1.22" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844" + integrity sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ== + +nanoid@^3.1.30: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +next-transpile-modules@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz#133b1742af082e61cc76b02a0f12ffd40ce2bf90" + integrity sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ== + dependencies: + enhanced-resolve "^5.7.0" + escalade "^3.1.1" + +next@12: + version "12.1.6" + resolved "https://registry.yarnpkg.com/next/-/next-12.1.6.tgz#eb205e64af1998651f96f9df44556d47d8bbc533" + integrity sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A== + dependencies: + "@next/env" "12.1.6" + caniuse-lite "^1.0.30001332" + postcss "8.4.5" + styled-jsx "5.0.2" + optionalDependencies: + "@next/swc-android-arm-eabi" "12.1.6" + "@next/swc-android-arm64" "12.1.6" + "@next/swc-darwin-arm64" "12.1.6" + "@next/swc-darwin-x64" "12.1.6" + "@next/swc-linux-arm-gnueabihf" "12.1.6" + "@next/swc-linux-arm64-gnu" "12.1.6" + "@next/swc-linux-arm64-musl" "12.1.6" + "@next/swc-linux-x64-gnu" "12.1.6" + "@next/swc-linux-x64-musl" "12.1.6" + "@next/swc-win32-arm64-msvc" "12.1.6" + "@next/swc-win32-ia32-msvc" "12.1.6" + "@next/swc-win32-x64-msvc" "12.1.6" + +node-fetch@^2.6.1: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-releases@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" + integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@8.4.5: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +prettier@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qrcode.react@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-3.0.2.tgz#7ceaea165aa7066253ef670a25bf238eaec4eb9e" + integrity sha512-8F3SGxSkNb3fMIHdlseqjFjLbsPrF3WvF/1MOboSUUHytT537W8f/FtbdA3XFIHDrc+TrRBjTI/QLmwhAIGWWw== + +querystring@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-number-format@^4.4.4: + version "4.9.3" + resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-4.9.3.tgz#338500fe9c61b1ac73c8d6dff4ec97dd13fd2b50" + integrity sha512-am1A1xYAbENuKJ+zpM7V+B1oRTSeOHYltqVKExznIVFweBzhLmOBmyb1DfIKjHo90E0bo1p3nzVJ2NgS5xh+sQ== + dependencies: + prop-types "^15.7.2" + +react-transition-group@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +reselect@^4.1.5: + version "4.1.6" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.6.tgz#19ca2d3d0b35373a74dc1c98692cdaffb6602656" + integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.12.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rifm@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4" + integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg== + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +styled-jsx@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729" + integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ== + +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +typescript@^4.1.3: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +whatwg-url@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== diff --git a/assets/bbg-256.png b/assets/bbg-256.png new file mode 100644 index 0000000000000000000000000000000000000000..a1dfbef63ed35a22e50cfdbcdca09170b53509bc GIT binary patch literal 13535 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 P|0QX{wP95%R+0Y)*RH+q literal 0 HcmV?d00001 diff --git a/assets/bbg-32.png b/assets/bbg-32.png new file mode 100644 index 0000000000000000000000000000000000000000..607bf150769fb29023f47cd7e8b117df51ef4f10 GIT binary patch literal 4592 zcma)92Ut_f5>7yoDqRBz#3)KlLeL-~L^`2&4Mib9fKZZ{gc78SQY;WD(yO5NswgOz zCKlu(AYD`hR4f-Ph$1RY@SOlEmxu3rC*Pjk%*;PC`_Jy4a}sT=OoaHQ`9UC%kSX5K z4(Oqr#>)fT8DU|cK_D=TY+ztxYG44hp;Nud0VEJeksXm@sbXjgxf`Y7+l1G5ve7*D zK%`^`+Rt08%|kk^x+Bm3V4765_WqV;{m05?0oT>0*9EAiRoNw_jfI0fwjJnF-*vFf zzKaz(s?{|U(kVX_`DB+*(%{zAs!Ienf{d)pBdl~5Y);~Y1EYa6_bXJ!X4>r;a_*X0-aUg|zh zZERKUd$K9)hU|IQn3oLu>d(ph*k`q~;_e!pha7opu9(xJpv^ra&$?qn|FFlpW7sLa zdiPz{6Gm=zM6Ie^9%)i8!tW4``;Iv>6znqC4I4;L{lIm^XNzBtmk3acOcKG=+tL!G z42*d}JYX>pH!uPNKM+_Nw0?060__9K{2U(yD=yn`0X8TQa0f{M%{!h9TDNQ;2K1Z@ z4>Z8jQjbES)G_nK4LOt)Krkc+k|+$IhB(x2^fG9* zW=*8iZ;>lBE0CO$VN3&wKBWC*FQ)HOxYfed_8guAf;daekwRwTP*}twVwHF`YB7oh ziQ@C$VV0$<5!Q4vP)H&t5QnBz-cYOO5qB?;`+tl$qXiy z&RS7qpwx>S*q(Ig-_jq70P^BSq!H;15@(s}z&KGk>-6W&{kbtYn8oFeVNku9Aw)V! z&j+9Yr|0cW2B>C1f$dH9p^)fMMJsAB6pDrd#~e}#i&zWvEBT-Pmz@(m7dfTTsa`>z zB(ERvW%2KEA-*JFMFIz_8WN?3L_7RASXGdFFi7MNH;Y!QonR51(e!XK7do%i^wGYUtU()uJH47+hc&2isg3-9K+5; zA8Kl3fL7N+qt#GwVAZZ^x2B)Pg94Zy38%3V_Dj5sS|V-5LBGi9k`#E1;P?Rse>{?K z{0`!|z*`V+jj5rY1A*_-{)m8#2a?~P%nePk279TBe<9rL(k@-tg>-06$bpD{Bp^@775w@v4=UmVT~} zcs7a)xyiUU2ql^O1P{*Px*Dd27@az!A)PwOjZwaxdPD&($7DQyRtBl#Kq!*PP>J`m z>L3=hjrZ5%Ba$XN!p8-Ar&9;wxKk*%?_^JF-(Bg^o#^VE*bhh2B_Aay`&Y2- z#&_2$e(bAkqkF>myZ`X(U)2@z*S3I6CP9o@IPLyGW#D!QfF5*@Fs*_GnKjjBH@kEYA9*qlw zWU-AMctj(qpKK+C!pdNT&S~{o)zk}EBhkmHNc-q^=*Ci^eWQDiol;4M_+%cye-{); zZ+6*{sMMp_E0I;m|B|_1^y{-SL-vVQJ;=$z`|AjQJ}gmCF-M0rI~B~Ox_rA2;ZII^ z9;TnLAgmUsugo^yP$1BU$vr2QU4AOPFs~)}>1csDI>#&0aaV6d&~xR2IuYmcGuAy% z>ccB%OZi@;fOK>%R8uX7EIl>)yhPMm1Cg~Qj<#-^9r?MT^mLPAuyk6Zr0m>HzRjXA ztffWxQ_7tkS?-}co^an>XUW0wl0$@-4n!f>QLFWN+t(L;kl7k&5?!p#Yvf!sryw26 zPkh}wdshCGZK+2*`$TgPOQw5AQ4>Mw$$2UK+gYl~tocbZkH-aeU0zo@io0ud<=xIa zgb`-qqT;hU_?&#E%4_xc9Gj{n9+fd}%Q*2GhBm+2x|2AOX#uI0CE2Fk(3H#gCoZP! zi^A{=fm_IW#clDDa@hipzqD_-Rp{HnlIGo-er@N>Y4ZWPbn*vso%z>)(o#-Qj=N~t zfQ{FO5)S_*mt%=Jsokhl4t;BI*42V9uGy$JeMixzhwMXO*EzkKRPEX`y$Q}C`IrB2 zw0Tg?2zc%s3?BUsmbfpSp%1s27A!x5C_PhGQ=QnDm36M$Z-OlAM6&EHZSx4fji<;b z(>=t{vCa#Eu`Y7ZLlz5LMk6*)bO@i8+O48&^08xc5!IPn6NR_j)z=o3ApBi);(~wl zH`mwHvH1LI2wX>ylxb{S4UL>1rFFQ}SSgH=cV;9?Qg$zRu!pR0ErNQIRt8tT>GgBh zKi`Pce>J7oF)Q~u`;xA8&VI9JHPTD($PC^bzy8fphW8o- zw~y*0=C;Pxza#z~_F*9|BU29-XtD0Rs7NRKtmz$p0$-H!bTd`tgVR0JKc&)cH#}N5 zH>76cH6Au7`aTpiE^_o8$_!y}JxWJ1jB9qJKIZAwg#7x{bAj$H`A~PaBlBMZ6P`tI zhy6X((6~!B20pB7X8*|{>cZbx^A?eNCvM3;=5@4f37XK7Jy<8QXKv$*uP>Vjd_(H9 z-?C+DAO3A6;217Fo`Z>_mwBRGDj0^O~e`D^78E*U9FF6 zAn?X=BuI8wiZ}SSsr?yvw6fB>D!1c5_`XnJ*%58JH?2 z3`@iw=h_snanoSv6FRm&;o+Nt^_Y!UAF>MCKI=xkzbpZ16#5LE#vGlb?TM0j9Z)8g z7WDlBZF84xOcw7ri*H=@5j>pt+D*%Y$BXvkI)wrRU1q+RY;acK&(z zH_F59SKA|_;^&Q&#)@>F!ny_XHA5N~D)k|-r&HX9T|-vk`7w26VoCh{j|z@GnRJZe z)$F!nOteTP=ghawODM2!^KBAPu(fb>z+D!|E-r|RMc6vTrrRSeDo#Ozm`?KS?UWSb z&4q;tdmFl^w#3d2ZfuJ3<-&KK=5cq=tczkFOVTX$u+Qy9-(TpN|^=aRO&(El2#tMIw zQ}m9k5%zm4*qmc!hwPJ=gUn7v>SK3Q_j+Ihqgx>78l%Xia0H-&TaW%Z=1sc z_VbJSaKoAUl9v((>Jkeh6*hkI@sp|g+Vgyp-@m8Sb)F!Z%Mx=TsPf2LI5yT*Z<)_Ws|=4E&0_FBJihi%ZTh?eMz z&{wF@sL2>FmQjdGP!mtzGG!MU0ulP7A(rG~mah++?=1rR(3+Kz-T= z497CxTWmm|Og`Uoig@(Bm|tVEL}B_>ZLimZj*=;oi5vT_QqK8*n^t=D$^Xsq+=ldq zV+^I*u7AuF#LJAYRmwkao|hMVp=OGTEXe#OCM@OlctMDj8-~9QY2MBG)HXG;GA!43 GkNpnZHeE@#GS>~pr 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 + +
API - KEY
API - KEY
bbgo/cmd/root.go 
bbgo/cmd/root.go 
bbgo/cmd/run.go
bbgo/cmd/run.go
pkg/bbgo/environment.go
pkg/bbgo/environment.go
pkg/bbgo/trader.go
pkg/bbgo/trader.go
pkg/strategy/grid/strategy.go
pkg/strategy/grid/strategy.go
API - KEY
API - KEY
Session
Session
DBDriver
DBDriver
Mysql
Mysql
Init
Init
userConfig.ExchangeStrategies
userConfig.ExchangeStrategies
bbgo.yaml
( file )
bbgo.yaml...
.env.local
( file )
.env.local...
Grid
Grid
Boll Grid
Boll Grid
pkg/strategy/bollgrid/strategy.go
pkg/strategy/bollgrid/strategy.go
... 
... 
pkg/strategy/.../strategy.go
pkg/strategy/.../strategy.go
FTX
FTX
Exchange
Exchange
低買
低買
高賣
高賣
1800 usd
1800 usd
1900 usd
1900 usd
2000 usd
2000 usd
2100 usd
2100 usd
2200 usd
2200 usd
遠東商銀
遠東商銀
其他銀行
其他銀行
Binance
Binance
API - KEY
API - KEY
...
...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/assets/screenshots/backtest-report.jpg b/assets/screenshots/backtest-report.jpg new file mode 100644 index 0000000000000000000000000000000000000000..adeeca0720095f23a974c91df6ca5a49fbada0f6 GIT binary patch literal 69289 zcmdSA1yo(h(lB~(f&>We?(Po3g9n0ZaCdit26wjr0fM``y9IZ52=4X{$z*2keD|~e zt^cj{>g?4eU0q$>yKQ&(d7gb<1t3a@ii-k3KmY&`;1BS;01yH|K|nx4fI~q-LPA49 zLBqa*g@u8EMMFS@e}jdFjfIJZiGf2vL4<=xhKGSk%s@g$MNLabi%rDD%1FaXK|@RP zVgv*V8XEQ$EGjH4Dh)0sF3tZMo;v_Y(4gNS0AL_Q08k_lFeH%YE&w*rNl>sCcmD)X z2oNwxa429T7RVp)XB+?o6bu{!@_8Nr2L?=t2!;qO=iS@C;{VqaWZ0dI)u`UriyY)} zRkJU1RILIv^YKI9t_~*6FPv$DkCh6}R`7JF_Z$D;&Jg{!{_dsIj!X7(h)ju;~z+V6jB7Sw@l(QUY9C;75T(};WAZnQKD&67#Zg3PpN zwCLP?0lB+∈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 literal 0 HcmV?d00001 diff --git a/assets/screenshots/dashboard.jpeg b/assets/screenshots/dashboard.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..96efd3e8b330fbe71dbad3e28fdcff45194fcf89 GIT binary patch literal 51497 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 literal 0 HcmV?d00001 diff --git a/assets/screenshots/setup-wizard-grid.jpeg b/assets/screenshots/setup-wizard-grid.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..77b02cf4c16060a49146f19aff60bdcb27617671 GIT binary patch literal 29353 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 z%0D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 tUTbSI6SCOd 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 literal 0 HcmV?d00001 diff --git a/assets/screenshots/setup-wizard.jpeg b/assets/screenshots/setup-wizard.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4a3b65008f988fe08b6431d2dbb18f14f3082a6c GIT binary patch literal 43494 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