├── .browserslistrc ├── .eslintignore ├── cypress.json ├── vue.config.js ├── cypress ├── fixtures │ ├── backtest.json │ ├── live.json │ ├── importCandles.json │ ├── deleteLive.json │ ├── updateConfig.json │ ├── deleteBacktest.json │ ├── deleteImportCandles.json │ ├── makeStrategy.json │ ├── feedback.json │ ├── login.json │ ├── logout.json │ ├── loginJesseTrade.json │ ├── generalInfo.json │ └── getConfig.json ├── server │ └── index.js ├── support │ ├── index.js │ └── commands.js ├── plugins │ └── index.js └── integration │ ├── importCandlePage.spec.js │ ├── livePage.spec.js │ ├── backtestPage.spec.js │ └── navbar.spec.js ├── public ├── favicon.ico └── index.html ├── babel.config.js ├── src ├── assets │ ├── imgs │ │ ├── equity-curve.png │ │ ├── logo-light.png │ │ ├── realtime-candle-chart.png │ │ ├── logo-dark.svg │ │ └── search-by-algolia-light-background.svg │ ├── styles │ │ ├── styles.css │ │ ├── _animations.css │ │ ├── _common.css │ │ └── _tailwind.css │ └── svg │ │ ├── moon-stars.svg │ │ └── sun.svg ├── components │ ├── Heading.vue │ ├── EmptyBox.vue │ ├── Card.vue │ ├── FullPageLoading.vue │ ├── Functional │ │ ├── DatePicker.vue │ │ ├── ImageLoader.vue │ │ ├── Spinner.vue │ │ ├── FormTextarea.vue │ │ ├── FormInput.vue │ │ ├── NumberInput.vue │ │ └── SlideOver.vue │ ├── StatsBox.vue │ ├── KeyValueTableSimple.vue │ ├── Tooltip.vue │ ├── Logs.vue │ ├── LoadingSvg.vue │ ├── DividerWithButtons.vue │ ├── Divider.vue │ ├── KeyValueTable.vue │ ├── Checkbox.vue │ ├── ThemeSwitch.vue │ ├── TablePlaceholder.vue │ ├── ToggleButton.vue │ ├── Modals │ │ ├── CustomModal.vue │ │ └── ConfirmModal.vue │ ├── Tables │ │ ├── InfoLogsTable.vue │ │ └── InfoTable.vue │ ├── Alert.vue │ ├── RadioGroups.vue │ ├── MultipleValuesTable.vue │ ├── Charts │ │ ├── EquityCurve.vue │ │ └── Candles │ │ │ └── CandlesChart.vue │ ├── UpdateBanner.vue │ ├── Tabs.vue │ └── Exception.vue ├── http.js ├── plugins │ ├── notyf.js │ ├── websocket.js │ └── socketActions.js ├── notifier.js ├── views │ ├── Candles.vue │ ├── Loading.vue │ ├── Backtest.vue │ ├── Live.vue │ ├── Optimization.vue │ ├── About.vue │ ├── Test.vue │ ├── LiveOrders.vue │ ├── MakeStrategy.vue │ ├── ReportLiveSession.vue │ ├── Feedback.vue │ ├── Home.vue │ ├── Login.vue │ ├── HelpSearch.vue │ └── tabs │ │ └── CandlesTab.vue ├── layouts │ └── LayoutWithSidebar.vue ├── App.vue ├── router │ └── index.js ├── main.js ├── helpers.js └── stores │ ├── candles.js │ ├── main.js │ └── backtest.js ├── postcss.config.js ├── .editorconfig ├── jest.config.js ├── .env.example ├── .gitignore ├── README.md ├── tests └── unit │ ├── test-helpers.spec.js │ └── TestSimpleComponents.spec.js ├── LICENSE ├── tailwind.config.js ├── .eslintrc.js └── package.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | last 2 years 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | other 2 | public 3 | cypress 4 | tests -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://127.0.0.1:8080/" 3 | } -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // assetsDir: 'static' 3 | } 4 | -------------------------------------------------------------------------------- /cypress/fixtures/backtest.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Started backtesting..." 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/live.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Started paper trading..." 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/importCandles.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Started importing candles..." 3 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-ai/dashboard/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /cypress/fixtures/deleteLive.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Live process with ID of 1 terminated." 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/updateConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Updated configurations successfully" 3 | } -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /cypress/fixtures/deleteBacktest.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Backtest process with ID of 1 terminated." 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/deleteImportCandles.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Candles process with ID of 1 terminated." 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/makeStrategy.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "success", 3 | "message": "strategies/test-strategy" 4 | } -------------------------------------------------------------------------------- /src/assets/imgs/equity-curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-ai/dashboard/HEAD/src/assets/imgs/equity-curve.png -------------------------------------------------------------------------------- /src/assets/imgs/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-ai/dashboard/HEAD/src/assets/imgs/logo-light.png -------------------------------------------------------------------------------- /cypress/fixtures/feedback.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "success", 3 | "message": "Feedback submitted successfully" 4 | } -------------------------------------------------------------------------------- /cypress/fixtures/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth_token": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" 3 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/styles/styles.css: -------------------------------------------------------------------------------- 1 | @import "_tailwind.css"; 2 | @import "_common.css"; 3 | @import "_animations.css"; 4 | 5 | -------------------------------------------------------------------------------- /src/components/Heading.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /cypress/fixtures/logout.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "Successfully logged out from Jesse.Trade and removed access_token file" 3 | } -------------------------------------------------------------------------------- /cypress/fixtures/loginJesseTrade.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "success", 3 | "message": "Successfully logged in to Jesse.Trade" 4 | } -------------------------------------------------------------------------------- /src/assets/imgs/realtime-candle-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-ai/dashboard/HEAD/src/assets/imgs/realtime-candle-chart.png -------------------------------------------------------------------------------- /src/http.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | axios.defaults.baseURL = process.env.VUE_APP_HTTP_PATH 4 | 5 | export default axios 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@vue/cli-plugin-unit-jest', 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/styles/_animations.css: -------------------------------------------------------------------------------- 1 | .fade-enter-active, 2 | .fade-leave-active { 3 | transition: opacity 0.3s ease; 4 | } 5 | .fade-enter-from, 6 | .fade-leave-to { 7 | opacity: 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/EmptyBox.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/assets/styles/_common.css: -------------------------------------------------------------------------------- 1 | /*svg {*/ 2 | /* fill: currentColor;*/ 3 | /*}*/ 4 | 5 | pre { 6 | overflow: auto; 7 | width: 100%; 8 | font-size: 12px; 9 | padding-bottom: 10px; 10 | margin-bottom: 0; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Card.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # For development create ".env.development.local" file 2 | 3 | VUE_APP_IS_DEBUG=yes 4 | # for production, set both of them to to "/" (yes even the ws) 5 | VUE_APP_SOCKET_PATH=ws://127.0.0.1:9000/ws 6 | VUE_APP_HTTP_PATH=http://127.0.0.1:9000 7 | 8 | -------------------------------------------------------------------------------- /src/plugins/notyf.js: -------------------------------------------------------------------------------- 1 | import { Notyf } from 'notyf' 2 | 3 | export default { 4 | install: (app, settings) => { 5 | settings.position.x = 'left' 6 | app.config.globalProperties.notyf = new Notyf(settings) 7 | app.notyf = app.config.globalProperties.notyf 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /cypress/server/index.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws') 2 | 3 | const wss = new WebSocket.Server({ port: 8001 }) 4 | 5 | wss.on('connection', function connection(ws) { 6 | const loginReply = JSON.stringify({ 7 | type: 'CONNECTED', 8 | }) 9 | 10 | ws.send(loginReply) 11 | }) 12 | -------------------------------------------------------------------------------- /src/notifier.js: -------------------------------------------------------------------------------- 1 | import { Notyf } from 'notyf' 2 | import 'notyf/notyf.min.css' 3 | 4 | const notifier = new Notyf({ 5 | duration: 5000, 6 | dismissible: true, 7 | ripple: false, 8 | position: { x: 'left', y: 'bottom' }, 9 | types: [ 10 | { 11 | type: 'info', 12 | background: '#009efa' 13 | } 14 | ] 15 | }) 16 | 17 | export default notifier 18 | -------------------------------------------------------------------------------- /src/components/FullPageLoading.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | .env 25 | 26 | package-lock.json 27 | 28 | cypress/videos 29 | cypress/screenshots -------------------------------------------------------------------------------- /src/assets/svg/moon-stars.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/components/Functional/DatePicker.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | -------------------------------------------------------------------------------- /cypress/fixtures/generalInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "exchanges": [ 3 | "Binance", 4 | "Binance Futures", 5 | "Binance Inverse Futures", 6 | "Bitfinex", 7 | "Coinbase", 8 | "OKEX", 9 | "Testnet Binance Futures" 10 | ], 11 | "live_exchanges": [ 12 | "Binance Futures", 13 | "FTX Futures", 14 | "Testnet Binance Futures" 15 | ], 16 | "strategies": [ 17 | "ExampleStrategy", 18 | "TestLiveMode01" 19 | ], 20 | "has_live_plugin_installed": true, 21 | "is_logged_in_to_jesse_trade": true, 22 | "cpu_cores": 8 23 | } -------------------------------------------------------------------------------- /src/components/StatsBox.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 28 | -------------------------------------------------------------------------------- /src/assets/svg/sun.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/components/Functional/ImageLoader.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | 36 | -------------------------------------------------------------------------------- /src/components/KeyValueTableSimple.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 27 | -------------------------------------------------------------------------------- /src/views/Candles.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | -------------------------------------------------------------------------------- /src/layouts/LayoutWithSidebar.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /src/components/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | -------------------------------------------------------------------------------- /src/views/Loading.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/Logs.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /src/views/Backtest.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /src/views/Live.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /src/components/LoadingSvg.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | -------------------------------------------------------------------------------- /src/components/DividerWithButtons.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 29 | -------------------------------------------------------------------------------- /src/views/Optimization.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | } 23 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 31 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /src/components/Functional/Spinner.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | 21 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dashboard 2 | 3 | This is the source code for the front end of Jesse's GUI dashboard. 4 | 5 | It is made using: 6 | - [VueCLI](https://cli.vuejs.org) 7 | - [VueJS 3](https://vuejs.org) 8 | - [TailwindCSS](https://tailwindcss.com) 9 | 10 | ## Project setup 11 | 12 | To install the dependencies, run: 13 | 14 | ```sh 15 | npm install 16 | ``` 17 | 18 | To compile and hot-reload for development: 19 | 20 | ```sh 21 | npm run serve 22 | ``` 23 | 24 | After doing so, you'll the URL, which by default is `http://localhost:8080`. To use it with Jesse, you also need to run Jesse using the good old `jesse run` command. 25 | 26 | to compile and minifies for production: 27 | ```sh 28 | npm run build 29 | ``` 30 | 31 | Lints and fixes files: 32 | 33 | ```sh 34 | npm run lint 35 | ``` 36 | 37 | ## Credits 38 | 39 | Many thanks to the contributors of this repository especially [Nicolay Zlobin](https://github.com/nicolay-zlobin) and [Morteza](https://github.com/morteza-koohgard) who helped a lot with the development of the initial version of the dashboard. -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Jesse 9 | 17 | 18 | 19 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/unit/test-helpers.spec.js: -------------------------------------------------------------------------------- 1 | import helpers from '@/helpers' 2 | 3 | 4 | test('test helpers.currentTime()', () => { 5 | expect(helpers.currentTime()) 6 | .toBe(new Date().toISOString().slice(11, 19)) 7 | }) 8 | 9 | test('test helpers.timestampToTime()', () => { 10 | expect(helpers.timestampToTime(1588888888000)) 11 | .toBe('2020-05-07 22:01:28') 12 | }) 13 | 14 | // test helpers.roundPrice() which is A helper function that rounds the input to 2 decimals but only if the number is bigger than 1. 15 | test('helpers.roundPrice()', () => { 16 | // for smaller than 1, it should stay the same 17 | expect(helpers.roundPrice(0.123456789)) 18 | .toBe(0.123456789) 19 | 20 | // for bigger than 1, it should round to 2 decimals 21 | expect(helpers.roundPrice(1.123456789)) 22 | .toBe(1.12) 23 | 24 | // if type of the input is not a number, return the input 25 | expect(helpers.roundPrice(undefined)) 26 | .toBe(undefined) 27 | expect(helpers.roundPrice(null)) 28 | .toBe(null) 29 | expect(helpers.roundPrice('string')) 30 | .toBe('string') 31 | }) 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jesse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/views/Test.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 49 | -------------------------------------------------------------------------------- /src/components/Functional/FormTextarea.vue: -------------------------------------------------------------------------------- 1 |