Giter Club home page Giter Club logo

futuresboard's Introduction

Futuresboard

A python (3.7+) based scraper and dashboard to monitor the performance of your Binance or Bybit Futures account.

GitHub Pipenv locked Python version License: GPL v3 FOSSA Status Code style: black

Version 2

Version 2 is currently in development and can be found in a separate branch. In short it manage multiple accounts from one dashboard and comes in darkmode.

Getting started

  • Create a fresh new API on Binance or Bybit, with only read rights.
  • Clone this repository: git clone https://github.com/ecoppen/futuresboard.git
  • Navigate to the futuresboard directory: cd futuresboard
  • Install dependencies python -m pip install .. For developing, python -m pip install -e .[dev]
  • Copy config/config.json.example to config/config.json and add your new api key and secret: nano config.json
  • Collect your current trades by running futuresboard --scrape-only. If you want to monitor the weight usage (see below).
  • By default, when launching the futuresboard web application, a separate thread is also started to continuously collect new trades. Alternatively, setup the scraper on a crontab or alternative to keep the database up-to-date: crontab -e then */5 * * * * futuresboard --scrape-only (example is every 5 minutes, change to your needs) In this case, don't forget to pass --disable-auto-scraper.
  • Start a screen or alternative if you want the webserver to persist: screen -S futuresboard
  • Start the futuresboard web application futuresboard
  • Navigate to the IP address shown e.g. http://127.0.0.1:5000/. These settings can be changed by passing --host and/or --port when running the above command

Currently only Binance and Bybit Futures are supported - as those are supported by passivbot.

API weight usage - Binance

  • Reminder: Binance API allows you to consume up to 1200 weight / minute / IP.
  • Account: Fetching account information costs 5 weight per run
  • Income: Fetching income information costs 30 weight per 1000 (initial run will build database, afterwards only new income will be fetched)
  • Orders: Fetching open order information costs 40 weight per run
  • The scraper will sleep for a minute when the rate exceeds 800 within a minute

API weight usage - Bybit

  • Account/Income/Positions: Fetching account information or positions costs 1 weight per run with a maximum combination allowed of 120/min. Income can be fetched in batches of 50 (initial run will build database, afters only new income will be fetched)
  • Orders: Fetching open order information costs 1 weight per symbol with a maximum allowed of 600/min
  • The scraper will sleep for a minute when the rate exceeds 100 within a minute

Customising the dashboard

The /config/config.json file allows you to customise the look and feel of your dashboard as follows:

  • AUTO_SCRAPE_INTERVAL is set to 300 seconds, this value can be adjusted between 60 and 3600
  • NAVBAR_TITLE changes the branding in the top left of the navigation (see below)
  • NAVBAR_BG changes the colour of the navigation bar, acceptable values are: bg-primary, bg-secondary, bg-success, bg-danger, bg-warning, bg-info and the default bg-dark
  • PROJECTIONS changes the percentage values on the projections page. 1.003 equates to 0.3% daily and 1.01 equates to 1% daily.

For example, setting "NAVBAR_TITLE": "Custom title" and "NAVBAR_BG": "bg-primary", would result in:

Screenshots

dashboard

calendar

coin

1h chart

history

positions

projection

License

FOSSA Status

Alternative dashboards

futuresboard's People

Contributors

aumanusorn avatar ecoppen avatar goldmang avatar krishna3114 avatar rluisr avatar s0undt3ch avatar sembsa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

futuresboard's Issues

Error after command 'futuresboad'

Traceback (most recent call last):
File "/usr/bin/futuresboard", line 33, in
sys.exit(load_entry_point('futuresboard', 'console_scripts', 'futuresboard')())
File "/usr/bin/futuresboard", line 22, in importlib_load_entry_point
for entry_point in distribution(dist_name).entry_points
File "/usr/lib/python3.8/importlib/metadata.py", line 503, in distribution
return Distribution.from_name(distribution_name)
File "/usr/lib/python3.8/importlib/metadata.py", line 177, in from_name
raise PackageNotFoundError(name)
importlib.metadata.PackageNotFoundError: futuresboard

Error on poisitons

I have internal server erro on Positions

[2022-01-18 10:51:56,932] INFO in scraper: Auto scrape routines terminated. Sleeping 600 seconds...
192.168.1.176 - - [18/Jan/2022 11:00:48] "GET / HTTP/1.1" 200 -
192.168.1.176 - - [18/Jan/2022 11:00:48] "GET /static/styles/dashboard.css HTTP/1.1" 304 -
192.168.1.176 - - [18/Jan/2022 11:00:48] "GET /static/styles/sidebars.css HTTP/1.1" 304 -
192.168.1.176 - - [18/Jan/2022 11:00:48] "GET /static/js/chartjs-chart-financial.js HTTP/1.1" 304 -
192.168.1.176 - - [18/Jan/2022 11:00:48] "GET /static/js/hammer.min.js HTTP/1.1" 304 -
192.168.1.176 - - [18/Jan/2022 11:00:49] "GET /static/favicon2.ico HTTP/1.1" 304 -
[2022-01-18 11:00:53,100] ERROR in app: Exception on /positions [GET]
Traceback (most recent call last):
  File "/home/dario/.local/lib/python3.8/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/dario/.local/lib/python3.8/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/dario/.local/lib/python3.8/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/dario/.local/lib/python3.8/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/home/dario/.local/lib/python3.8/site-packages/futuresboard/blueprint.py", line 603, in positions_page
    return render_template(
  File "/home/dario/.local/lib/python3.8/site-packages/flask/templating.py", line 147, in render_template
    return _render(
  File "/home/dario/.local/lib/python3.8/site-packages/flask/templating.py", line 128, in _render
    rv = template.render(context)
  File "/home/dario/.local/lib/python3.8/site-packages/jinja2/environment.py", line 1291, in render
    self.environment.handle_exception()
  File "/home/dario/.local/lib/python3.8/site-packages/jinja2/environment.py", line 925, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/home/dario/.local/lib/python3.8/site-packages/futuresboard/templates/positions.html", line 1, in top-level template code
    {% extends "base.html" %}
  File "/home/dario/.local/lib/python3.8/site-packages/futuresboard/templates/base.html", line 108, in top-level template code
    <div id="content">{% block content %}{% endblock %}</div>
  File "/home/dario/.local/lib/python3.8/site-packages/futuresboard/templates/positions.html", line 47, in block 'content'
    <td>{{ ((1-positions[coin][2][4]/markprices[coin])*100)|round(2)}}%</td>
TypeError: unsupported operand type(s) for /: 'str' and 'float'
192.168.1.176 - - [18/Jan/2022 11:00:53] "GET /positions HTTP/1.1" 500 -
192.168.1.176 - - [18/Jan/2022 11:00:53] "GET /favicon.ico HTTP/1.1" 404 -
192.168.1.176 - - [18/Jan/2022 11:00:54] "GET /static/favicon2.ico HTTP/1.1" 304 -

Bybit no longer compatible due to API change?

The error I am getting upon starting futuresboard using bybit:

Traceback (most recent call last): File "/home/ubuntu/.local/bin/futuresboard", line 8, in <module> sys.exit(main()) File "/home/ubuntu/.local/lib/python3.8/site-packages/futuresboard/cli.py", line 64, in main futuresboard.scraper.scrape() File "/home/ubuntu/.local/lib/python3.8/site-packages/futuresboard/scraper.py", line 274, in scrape _scrape(app=app) File "/home/ubuntu/.local/lib/python3.8/site-packages/futuresboard/scraper.py", line 530, in _scrape if responseJSON["result"]["data"] is not None: KeyError: 'data'

Have asked others about the issue in PB discord, it appears works fine on Binance but no longer on Bybit. I looked through their API changes and cannot seem to spot a modification that could be causing this error.

Distance in % is 0.00% for prices < 1

int function should be removed in positions.html:

43c43
<                             <td>{% if positions[coin][2][4] != "-" %}{{ ((positions[coin][2][5]|int/markprices[coin])*100)|round(2)}}% {% endif %}</td>
---
>                             <td>{% if positions[coin][2][4] != "-" %}{{ ((positions[coin][2][5]/markprices[coin])*100)|round(2)}}% {% endif %}</td>
47c47
<                             <td>{% if positions[coin][2][6] != "-" %}{{ ((positions[coin][2][7]|int/markprices[coin])*100)|round(2)}}% {% endif %}</td>
---
>                             <td>{% if positions[coin][2][6] != "-" %}{{ ((positions[coin][2][7]/markprices[coin])*100)|round(2)}}% {% endif %}</td>
61c61
<                             <td>{% if positions[coin][2][8] != "-" %}{{ ((positions[coin][2][9]|int/markprices[coin])*100)|round(2)}}% {% endif %}</td>
---
>                             <td>{% if positions[coin][2][8] != "-" %}{{ ((positions[coin][2][9]/markprices[coin])*100)|round(2)}}% {% endif %}</td>
65c65
<                             <td>{% if positions[coin][2][10] != "-" %}{{ ((positions[coin][2][11]|int/markprices[coin])*100)|round(2)}}% {% endif %}</td>
---
>                             <td>{% if positions[coin][2][10] != "-" %}{{ ((positions[coin][2][11]/markprices[coin])*100)|round(2)}}% {% endif %}</td>

500 internal error

[2022-03-19 20:57:06,807] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/flask/app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.8/dist-packages/flask/app.py", line 1518, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.8/dist-packages/flask/app.py", line 1516, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.8/dist-packages/flask/app.py", line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/usr/local/lib/python3.8/dist-packages/futuresboard/blueprint.py", line 340, in index_page
coin_list=get_coins(),
File "/usr/local/lib/python3.8/dist-packages/futuresboard/blueprint.py", line 103, in get_coins
pbr = round(calc_pbr(position[3], position[1], position[2], float(balance[0])), 2)
File "/usr/local/lib/python3.8/dist-packages/futuresboard/blueprint.py", line 69, in calc_pbr
return abs(volume * price) / balance
ZeroDivisionError: float division by zero
188.255.34.222 - - [19/Mar/2022 20:57:06] "GET / HTTP/1.1" 500 -

/positions URL includes SHORTs where only LONGs are active ( Binance only )

For SYMBOLS, where LONG positions are active, /positions URL also displays SHORT row with 0 volume ( probably as well the other way around )

Changing 49th line in positions.html as below does help, however it might be better not to populate positions array with zero valued positions, probably somewhere in blueprint.py ( I'm not that familiar with python syntax )


49c49
<                     {% if positions[coin][0]|length > 1 %}
---
>                     {% if positions[coin][0]|length > 1 and positions[coin][0][1][6] != 0 %}


Unified Trading Account

Hello,

It would be great if you could add support for ByBits new Unified Trading Account.

I have upgraded to Unified Trading Account & the dashboard throws errors. When i tried updating the wallet-balance api request from CONTRACT to UNIFIED, when starting futuresboard, it still throws an error regarding it using CONTRACT still

Not sure how i'll fix this, but would be great if you added support for UTA in config

Some route error with Nginx

Dear Pro,

Thank you for your dashboard. All things are nice

I'm testing some routes not working

/history/
0|futuresb | return self._get_source_fast(environment, template)
0|futuresb | File "/usr/local/lib/python3.8/dist-packages/flask/templating.py", line 95, in _get_source_fast
0|futuresb | raise TemplateNotFound(template)
0|futuresb | jinja2.exceptions.TemplateNotFound: history.html
0|futuresb | 127.0.0.1 - - [18/Nov/2021 00:12:37] "GET /history/ HTTP/1.1" 500 -

and others not important:

  • /coins/active
  • /coins/inactive
  • /coins/totals

Coins don't show up as active.

Coins will not show up as active if they've never closed a trade (no pnl). Additionally if they have an open position but no buy/sell orders, these coins also don't show up in the dashboard. Could be fixed by adding a bool based on position size to the active/inactive coin logic. Specifically, mark a coin as active if it has a current position, a sell, or a buy.

Not a bug, feature update

I really love the 7day average projection it would be really cool that when clicking "Projection" button on the graph to calculate the projection the average calculated not using the standard 7 days but the selected range of the graph in case is different from the 7 days.

App crashes on positions request

I'm using bybit and running futuresboard using docker-compose.
The app triggered an exception and returned 500 Internal Server Error for me once (very rarely), probably because of unexpected value from the data...

futuresboard_1  | [2022-11-29 22:41:44,265] ERROR in app: Exception on /positions [GET]
futuresboard_1  | Traceback (most recent call last):
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 2525, in wsgi_app
futuresboard_1  |     response = self.full_dispatch_request()
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1822, in full_dispatch_request
futuresboard_1  |     rv = self.handle_user_exception(e)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1820, in full_dispatch_request
futuresboard_1  |     rv = self.dispatch_request()
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1796, in dispatch_request
futuresboard_1  |     return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/blueprint.py", line 665, in positions_page
futuresboard_1  |     return render_template(
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/templating.py", line 147, in render_template
futuresboard_1  |     return _render(app, template, context)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/flask/templating.py", line 130, in _render
futuresboard_1  |     rv = template.render(context)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 1301, in render
futuresboard_1  |     self.environment.handle_exception()
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 936, in handle_exception
futuresboard_1  |     raise rewrite_traceback_stack(source=source)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/templates/positions.html", line 1, in top-level template code
futuresboard_1  |     {% extends "base.html" %}
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/templates/base.html", line 113, in top-level template code
futuresboard_1  |     <div id="content">{% block content %}{% endblock %}</div>
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/templates/positions.html", line 39, in block 'content'
futuresboard_1  |     <td>{{ markprices[coin]|round(8)}}</td>
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/jinja2/filters.py", line 1141, in do_round
futuresboard_1  |     return round(value, precision)
futuresboard_1  | TypeError: type Undefined doesn't define __round__ method
futuresboard_1  | *.*.*.* - - [29/Nov/2022 22:41:44] "GET /positions HTTP/1.1" 500 -

feature request

Would be nice to have on the the position table also the position size in quote currency.
Currenly is volume and price (need to make the calculation by hand).

Subaccount keys show main account balances

Using Bybit subaccount keys, I want to only see the total balances and trades from this subaccount, however futuresboard also shows the trades from the parent account. Is there a way to filter those trades out?

not showing after update

Hello! After update no showing "Profit today", "Profit in August" and "Profit from Monday".
New api key with read only

Z5lUuRzlkfVEgbEG2uy4LLQkuIn7Fr5E1eWpuQZeHJRawyw6JMIBSV0xRhNi6X2Z
cVurRya3xuCQL0CD9mL76OZxrJOxaKETjpa1oRlGn1iolQt9KAy7lVcbOKcgBoNH

Scraper crashes rarely because TypeError

I'm using bybit, and running futures bot using docker-compose:

futuresboard_1  | [2022-11-29 14:25:36,695] INFO in scraper: Auto scrape routines starting
futuresboard_1  | Exception in thread Thread-1:
futuresboard_1  | Traceback (most recent call last):
futuresboard_1  |   File "/usr/local/lib/python3.8/threading.py", line 932, in _bootstrap_inner
futuresboard_1  |     self.run()
futuresboard_1  |   File "/usr/local/lib/python3.8/threading.py", line 870, in run
futuresboard_1  |     self._target(*self._args, **self._kwargs)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/scraper.py", line 43, in _auto_scrape
futuresboard_1  |     scrape(app=app)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/scraper.py", line 280, in scrape
futuresboard_1  |     _scrape(app=app)
futuresboard_1  |   File "/usr/local/lib/python3.8/site-packages/futuresboard/scraper.py", line 421, in _scrape
futuresboard_1  |     for position in responseJSON["result"]:
futuresboard_1  | TypeError: 'NoneType' object is not iterable
futuresboard_1  | *.*.*.* - - [29/Nov/2022 20:43:13] "GET / HTTP/1.1" 200 -

The response should be validated before access. I tried looking into the code to fix it, but this section looks too complicated for someone unfamiliar with the code...

Publishing in Docker Hub

Hi!

This is a great tool, i am loving it! Would it be possible to for someone to put this on docker hub?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.