Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) update readme and bots manager ui #60

Merged
merged 1 commit into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,43 @@
## Requirements

You will need to install [StreamLit](https://streamlit.io/). For information about Streamlit installation, see the instructions located at https://docs.streamlit.io/library/get-started/installation.

You will also need to install either [Anaconda](https://www.anaconda.com/) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html) to get Conda:
* [Anaconda](https://www.anaconda.com/) is a comprehensive Python distribution that includes a large number of pre-installed data science libraries and packages. It is designed to be an all-in-one solution for data science and machine learning tasks. When you install Anaconda, it comes with a collection of popular Python packages like NumPy, pandas, matplotlib, scikit-learn, and more.
* [Miniconda](https://docs.conda.io/en/latest/miniconda.html) is a minimal version of Anaconda. It includes only the essential components, such as Python interpreter and Conda package manager. Unlike Anaconda, Miniconda doesn't come with pre-installed packages, which makes its download size much smaller.

This repository is maintained by Hummingbot Foundation as a companion for users of [Hummingbot](https://github.com/hummingbot/hummingbot), the open source framework for building high-frequency crypto trading bots.

Watch this video to understand how it works:
https://www.loom.com/share/72d05bcbaf4048a399e3f9247d756a63

## Requirements

* 8 GB memory or more (On AWS, this is a `t2.large` instance)
* Linux / Debian / MacOS

## Installation

1. Install Steamlit and Conda packages utilizing their instructions for your specific environment:
* Install [StreamLit](https://docs.streamlit.io/library/get-started/installation)
* Install [Anaconda](https://docs.anaconda.com/free/anaconda/install/index.html) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html)
1 - Install dependencies:

* [Docker Engine](https://docs.docker.com/engine/install/ubuntu/)
* [Miniconda](https://docs.conda.io/en/latest/miniconda.html) or [Anaconda](https://www.anaconda.com/):

2. Clone this repo and navigate to the created directory
2 - Clone repo and navigate to the created directory
```bash
git clone https://github.com/hummingbot/dashboard.git
cd dashboard
```

3. Run command to create an isolated `conda` environment and install dependencies
```
3 - Create `conda` environment and install dependencies
```bash
make env_create
```

4. Activate the isolated 'conda' environment
4 - Activate the isolated 'conda' environment
```bash
conda activate dashboard
```

5. Run the app
5 - Start the dashboard
```bash
streamlit run main.py
```

## Data Feed

Your `dashboard` environment needs to have access to the database for your Hummingbot environment. This is done by setting up a symbolic link to the 'data' directory of your running Hummingbot instance.

The data directory differs for Docker versus Source installed Hummingbot. Data directory for each is as follows:
* Docker installed: /path/to/hummingbot/hummingbot_files/data
* Source installed: /path/to/hummingbot/data


Create a symlink to your Hummingbot `/data` directory
```bash
# replace `/path/to/hummingbotdata` with the actual path
ln -s /path/to/hummingbotdata data

# if you need to remove the symlink
unlink data
```

## Updating Dependencies
## Updating

To update the `dashboard` environment for changes to dependencies defined in `environment.yml`, remove the environment and re-create it:
```
Expand All @@ -69,3 +50,29 @@ To updated the `dashboard` source for latest version, run:
cd dashboard
git pull
```

## Troubleshooting

### Docker permissions

If you get an error like `Permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock`, run this command to enable Docker permissions:
```
sudo chmod 6666 /var/run/docker.sock
```

### Sym-link data directory

To use the [Strategy Performance page](https://github.com/hummingbot/dashboard/wiki/%F0%9F%9A%80-Strategy-Performance), you need to establish a symbolic link to the `data` directory of your running Hummingbot instance:

The `data` directory differs for Docker versus Source installed Hummingbot:
* Docker installed: `/path/to/hummingbot/hummingbot_files/data`
* Source installed: `/path/to/hummingbot/data`

Create a symlink to your Hummingbot `/data` directory
```bash
# replace `/path/to/hummingbotdata` with the actual path
ln -s /path/to/hummingbotdata data

# if you need to remove the symlink
unlink data
```
16 changes: 5 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Hummingbot Dashboard is a community project to build dashboards that help you de

Here are the current dashboards in the collection:

* 🚀 **Strategy Performance**: Analyze the performance of a running Hummingbot instance
* 🐙 **Bot Orchestration**: Deploy and manage Hummingbot instances
* ⚙️ **Backtest Manager**: Deploy and manage backtests of directional strategies
* ⚙️ **Backtest Manager**: Backtest strategies against historical data and optimize hyper-parameters
* 🚀 **Strategy Performance**: Analyze the performance of a running Hummingbot instance
* 🗂 **Candles Downloader**: Download historical exchange data as OHLVC candles. Supports multiple trading pairs and custom time ranges/intervals.
* 🔍 **DB Inspector**: Inspect and analyze the orders and trades data contained in a Hummingbot strategy database
* 🧙 **Token Spreads**: Identify cross-exchange trading opportunities by analyzing differences in token spreads across venues
Expand All @@ -18,14 +18,8 @@ This project is built using [StreamLit](https://streamlit.io/) and uses Anaconda

See [Installation](https://github.com/hummingbot/dashboard/blob/main/INSTALLATION.md) for how to install and update the dashboard.

### Contributions

We welcome contributions from the community! See [Contribution](https://github.com/hummingbot/dashboard/blob/main/CONTRIBUTING.md) for more information.

### Meetings

We hold bi-weekly livestream Dashboard project meetings. You can participate on our [Discord](https://discord.gg/hummingbot)
* Alternating Wenesdays, 3pm GMT / 11am EST / 8am PST / 11pm SIN
* Design, Status, Demos, etc
### Contributions and feedback

We welcome contributions from the community! See [Contributing](https://github.com/hummingbot/dashboard/blob/main/CONTRIBUTING.md) for more information.

To provide feedback, submit a [Github issue](https://github.com/hummingbot/dashboard/issues) or join the #dashboard channel in our [Discord](https://discord.gg/hummingbot).
30 changes: 18 additions & 12 deletions pages/bot_orchestration/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from ui_components.exited_bot_card import ExitedBotCard
from utils.st_utils import initialize_st_page

initialize_st_page(title="Bot Orchestration", icon="🐙", initial_sidebar_state="expanded")
initialize_st_page(title="Bots Manager", icon="🦅", initial_sidebar_state="collapsed")

if "is_broker_running" not in st.session_state:
st.session_state.is_broker_running = False
Expand Down Expand Up @@ -118,37 +118,43 @@ def get_grid_positions(n_cards: int, cols: int = NUM_CARD_COLS, card_width: int


with elements("create_bot"):
with mui.Grid(container=True, spacing=4):
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=6):
with mui.Paper(style={"padding": "2rem"}, variant="outlined"):
with mui.Grid(container=True, spacing=4):
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=12):
mui.Typography("🚀 Create Instance", variant="h4")
mui.Typography("🚀 Create Instance", variant="h5")
with mui.Grid(item=True, xs=8):
mui.TextField(label="Bot Name", variant="outlined", onChange=lazy(sync("new_bot_name")),
sx={"width": "100%"})
with mui.Grid(item=True, xs=4):
with mui.Button(onClick=launch_new_bot, variant="contained", color="success"):
with mui.Button(onClick=launch_new_bot,
variant="outlined",
color="success",
sx={"width": "100%", "height": "100%"}):
mui.icon.AddCircleOutline()
mui.Typography("Create")
with mui.Grid(item=True, xs=6):
with mui.Paper(style={"padding": "2rem"}, variant="outlined"):
with mui.Grid(container=True, spacing=4):
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=12):
mui.Typography("🐙 Manage Broker", variant="h4")
mui.Typography("🐙 Manage Broker", variant="h5")
with mui.Grid(item=True, xs=8):
mui.Typography("Hummingbot Broker helps you control and monitor your bot instances.")
with mui.Grid(item=True, xs=4):
button_text = "Stop Broker" if st.session_state.is_broker_running else "Start Broker"
button_text = "Stop" if st.session_state.is_broker_running else "Start"
color = "error" if st.session_state.is_broker_running else "success"
icon = mui.icon.Stop if st.session_state.is_broker_running else mui.icon.PlayCircle
with mui.Button(onClick=manage_broker_container, color=color, variant="contained"):
with mui.Button(onClick=manage_broker_container,
color=color,
variant="outlined",
sx={"width": "100%", "height": "100%"}):
icon()
mui.Typography(button_text)

with elements("active_instances_board"):
with mui.Paper(style={"padding": "2rem"}, variant="outlined"):
mui.Typography("🦅 Active Instances", variant="h4")
with mui.Paper(sx={"padding": "2rem"}, variant="outlined"):
mui.Typography("🦅 Active Instances", variant="h5")
if st.session_state.is_broker_running:
quantity_of_active_bots = len(st.session_state.active_bots)
if quantity_of_active_bots > 0:
Expand All @@ -174,7 +180,7 @@ def get_grid_positions(n_cards: int, cols: int = NUM_CARD_COLS, card_width: int
st.session_state.exited_bots[exited_instance] = ExitedBotCard(exited_instances_board, x, y,
CARD_WIDTH, 1)
with mui.Paper(style={"padding": "2rem"}, variant="outlined"):
mui.Typography("💤 Inactive Instances", variant="h4")
mui.Typography("💤 Stopped Instances", variant="h5")
with exited_instances_board():
for bot, card in st.session_state.exited_bots.items():
card(bot)
46 changes: 28 additions & 18 deletions ui_components/bot_performance_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,46 +40,56 @@ def __call__(self, bot_config: dict):
with mui.Card(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 2, "overflow": "auto"},
elevation=2):
color = "green" if bot_config["is_running"] else "red"
subheader_message = "Running " + st.session_state.active_bots[bot_name]["selected_strategy"] if bot_config["is_running"] else "Stopped"
color = "green" if bot_config["is_running"] else "grey"
subheader_message = "Running " + st.session_state.active_bots[bot_name]["selected_strategy"] if bot_config["is_running"] else "Not running"
mui.CardHeader(
title=bot_config["bot_name"],
subheader=subheader_message,
avatar=mui.Avatar("🤖", sx={"bgcolor": color}),
action=mui.IconButton(mui.icon.Stop, onClick=lambda: bot_config["broker_client"].stop()) if bot_config[
"is_running"] else mui.IconButton(mui.icon.BuildCircle),
# action=mui.IconButton(mui.icon.Stop, onClick=lambda: bot_config["broker_client"].stop()) if bot_config[
# "is_running"] else mui.IconButton(mui.icon.BuildCircle),
className=self._draggable_class,
)
if bot_config["is_running"]:
with mui.CardContent(sx={"flex": 1}):
with mui.Paper(elevation=2, sx={"padding": 2, "marginBottom": 2}):
mui.Typography("Status", variant="h6")
mui.Typography(bot_config["status"])
mui.Typography("Status")
mui.Typography(bot_config["status"], sx={"fontSize": "0.75rem"})
with mui.Accordion(sx={"padding": 2, "marginBottom": 2}):
with mui.AccordionSummary(expandIcon="▼"):
mui.Typography("Trades" + "(" + str(len(bot_config["trades"])) + ")", variant="h6")
mui.Typography("Trades" + "(" + str(len(bot_config["trades"])) + ")")
with mui.AccordionDetails():
mui.Typography(str(bot_config["trades"]))
mui.Typography("Run the following command in Bash/Terminal to attach to the bot instance:")
mui.TextField(disabled=True, value="docker attach " + bot_name, sx={"width": "100%"})

mui.Typography(str(bot_config["trades"]), sx={"fontSize": "0.75rem"})
else:
with mui.CardContent(sx={"flex": 1}):
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=12):
mui.Typography("Select a strategy:")
mui.Typography("Select a strategy config file (.yml) or script (.py) to run:")
with mui.Grid(item=True, xs=8):
with mui.Select(onChange=lazy(lambda x, y: self.set_strategy(x, y, bot_name)),
sx={"width": "100%"}):
for strategy in strategies:
mui.MenuItem(strategy, value=strategy, divider=True, sx={"fontWeight": "bold"})
for script in scripts:
mui.MenuItem(script, value=script)
for strategy in strategies:
mui.MenuItem(strategy, value=strategy)
with mui.Grid(item=True, xs=4):
with mui.Button(onClick=lambda x: self.start_strategy(bot_name, bot_config["broker_client"]), variant="contained", color="success"):
with mui.Button(onClick=lambda x: self.start_strategy(bot_name, bot_config["broker_client"]),
variant="outlined",
color="success",
sx={"width": "100%", "height": "100%"}):
mui.icon.PlayCircle()
mui.Typography("Start")
with mui.CardActions():
with mui.Button(onClick=lambda: DockerManager().stop_container(bot_name), variant="contained", color="error"):
mui.icon.DeleteForever()
mui.Typography("Stop Instance")
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=6):
with mui.Button(onClick=lambda: DockerManager().stop_container(bot_name),
variant="outlined",
color="error",
sx={"width": "100%", "height": "100%"}):
mui.icon.DeleteForever()
mui.Typography("Stop Instance")
with mui.Grid(item=True, xs=6):
mui.TextField(disabled=True,
label="Attach to bot instance",
value="docker attach " + bot_name,
sx={"width": "100%"})
25 changes: 17 additions & 8 deletions ui_components/exited_bot_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,28 @@ def remove_container(bot_name):

def __call__(self, bot_name: str):
with mui.Card(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
sx={"display": "flex", "flexDirection": "column", "borderRadius": 2, "overflow": "auto"},
elevation=2):
mui.CardHeader(
title=bot_name,
subheader="Stopped",
avatar=mui.Avatar("💀", sx={"bgcolor": "grey"}),
avatar=mui.Avatar("💀", sx={"bgcolor": "black"}),
className=self._draggable_class,
)

with mui.CardActions():
with mui.Button(onClick=lambda: DockerManager().start_container(bot_name), variant="contained", color="success", sx={"pr": "2"}):
mui.icon.PlayCircle()
mui.Typography("Start Container")
with mui.Button(onClick=lambda: self.remove_container(bot_name), variant="contained", color="error"):
mui.icon.DeleteForever()
mui.Typography("Delete Container")
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=6):
with mui.Button(onClick=lambda: DockerManager().start_container(bot_name),
variant="outlined",
color="success",
sx={"width": "100%"}):
mui.icon.PlayCircle()
mui.Typography("Start Instance")
with mui.Grid(item=True, xs=6):
with mui.Button(onClick=lambda: self.remove_container(bot_name),
variant="outlined",
color="error",
sx={"width": "100%"}):
mui.icon.DeleteForever()
mui.Typography("Delete Instance")