diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5253cb8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,91 @@ +name: Freqtrade TUI CI + +on: + push: + branches: + - main + - ci/* + release: + types: [published] + pull_request: + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}" + cancel-in-progress: true +permissions: + repository-projects: read + + + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ "ubuntu-20.04", "ubuntu-22.04", "macos-12", "macos-13", "macos-14", "windows-latest" ] + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install ruff + + - name: Run Ruff + run: | + ruff check --output-format=github + + # - name: Run Ruff format check + # run: | + # ruff format --check + + publish: + name: "Deploy to pypi" + if: (github.event_name == 'release') + environment: + name: release + url: https://pypi.org/p/ftui + + permissions: + id-token: write + + needs: build + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install build + + + - name: Build package + run: | + pip install -U build + python -m build + + - name: Publish to PyPI (Test) + uses: pypa/gh-action-pypi-publish@v1.8.14 + with: + repository-url: https://test.pypi.org/legacy/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@v1.8.14 diff --git a/README.md b/README.md index a892627..9f613f2 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ for running Freqtrade bots. Currently, FTUI is only supported on Linux systems. We hope to provide a Docker container in future. +The easiest way to install FTUI is via pip: `pip install ftui` + __Linux__ FTUI can be installed into an existing venv (e.g. a existing freqtrade venv) or in a @@ -37,15 +39,13 @@ $ cd ftui $ python3 -m venv .venv $ source .venv/bin/activate $ pip3 install -r requirements.txt -$ pip3 install freqtrade-ftui +$ pip3 install -e . ``` Once installed, a `config.yaml` needs to be provided to FTUI, so create it in your new `ftui/` directory and edit it with a cli text editor like `nano`: ```bash -$ pwd -/home/froggleston/ftui $ touch config.yaml $ nano config.yaml ``` diff --git a/ftui/__init__.py b/ftui/__init__.py index 3dc1f76..485f44a 100644 --- a/ftui/__init__.py +++ b/ftui/__init__.py @@ -1 +1 @@ -__version__ = "0.1.0" +__version__ = "0.1.1" diff --git a/ftui/ftui.py b/ftui/ftui.py index 87c903b..60c5597 100644 --- a/ftui/ftui.py +++ b/ftui/ftui.py @@ -25,14 +25,9 @@ import pandas as pd -from rich.progress import Progress, BarColumn, TextColumn -from rich.rule import Rule -from rich.style import Style -from rich.table import Table from textual import work from textual.app import App -from textual.color import Color from textual.logging import TextualHandler from textual.reactive import reactive, var @@ -446,12 +441,12 @@ def action_show_trade_info_dialog(self, trade_id, cl_name) -> None: tis.client = self.client_dict[cl_name] self.push_screen(tis) - def action_open_link(self, link) -> None: - try: - webbrowser.open(link, new=2) - except Exception as e: - print(f"Error opening link: {e}") - pass + # def action_open_link(self, link) -> None: + # try: + # webbrowser.open(link, new=2) + # except Exception as e: + # print(f"Error opening link: {e}") + # pass def setup(args): diff --git a/ftui/ftui_helpers.py b/ftui/ftui_helpers.py index 3042a25..a7b1c8d 100644 --- a/ftui/ftui_helpers.py +++ b/ftui/ftui_helpers.py @@ -1,5 +1,4 @@ import requests -import webbrowser from datetime import datetime @@ -12,7 +11,6 @@ from textual.color import Color from textual._color_constants import COLOR_NAME_TO_RGB -import freqtrade_client.ft_rest_client as ftrc class FtuiColours(dict[str, Color]): @@ -409,17 +407,11 @@ def bot_general_info(client) -> str: def bot_general_metrics_table(client) -> str: config = client.get_client_config() - TZFMT = "%Y-%m-%d %H:%M:%S%z" - t = client.get_total_profit() if t is None: return "[ERROR] Could not retrieve profit data." - pcc = round(float(t["profit_closed_coin"]), 2) - best_pair = t["best_pair"] - trade_count = t["trade_count"] - closed_trade_count = t["closed_trade_count"] profit_factor = round(t['profit_factor'], 2) if t['profit_factor'] is not None else "-" @@ -435,7 +427,7 @@ def bot_general_metrics_table(client) -> str: f"(∑ {round(t['profit_all_ratio_sum']*100, 2)}%)", ), ( - f"ROI all trades", + "ROI all trades", f"{round(t['profit_all_coin'], 2)} {config['stake_currency']} " f"({chr(0x03BC)} {round(t['profit_all_ratio_mean']*100, 2)}%)", ), @@ -451,7 +443,7 @@ def bot_general_metrics_table(client) -> str: (f"Trading volume", f"{round(t['trading_volume'], 2)} {config['stake_currency']}"), (f"Profit factor", f"{profit_factor}"), ( - f"Max Drawdown", + "Max Drawdown", f"{round(t['max_drawdown']*100, 2)}% " f"({round(t['max_drawdown_abs'], 2)} {config['stake_currency']}) " f"from {t['max_drawdown_start']} to {t['max_drawdown_end']}", diff --git a/ftui/ftui_screens.py b/ftui/ftui_screens.py index 49b9fbd..fca68a3 100644 --- a/ftui/ftui_screens.py +++ b/ftui/ftui_screens.py @@ -1,4 +1,3 @@ -import webbrowser from pathlib import Path from datetime import datetime, timezone @@ -6,13 +5,11 @@ import pandas as pd import numpy as np -from rich.style import Style from rich.table import Table from rich.text import Text from textual import work, on from textual.app import ComposeResult -from textual.color import Color from textual.containers import Container, Horizontal, Vertical from textual_plotext import PlotextPlot from textual.screen import Screen, ModalScreen @@ -27,12 +24,8 @@ Input, Label, ListView, - ListItem, Log, - Markdown, - MarkdownViewer, ProgressBar, - Rule, Select, Sparkline, Static, @@ -1177,7 +1170,7 @@ def _render_chart(self, ftuic, pair, data): self.app.call_from_thread(chart_container.refresh) else: self.notify( - f"Please try clicking Refresh above to retry", + "Please try clicking Refresh above to retry", title=f"Error: No data available for {pair}", severity="warning", ) @@ -1308,7 +1301,7 @@ def update_sysinfo_tab(self, tab_id, bot_id): client_dict = self.app.client_dict cl = client_dict[bot_id] - data = self._render_sysinfo(cl) + self._render_sysinfo(cl) def _render_sysinfo(self, ftuic): sysinfo = ftuic.get_sys_info() @@ -1432,7 +1425,7 @@ async def on_mount(self) -> None: msg = f"Unable to load help file: {self.help_file_path!r}" self.notify( msg, - title=f"Error:", + title="Error:", severity="warning", )