From 9004192169493682d65334a40080cdcc2c5313ee Mon Sep 17 00:00:00 2001 From: carkod Date: Sat, 9 May 2026 19:17:26 +0100 Subject: [PATCH 1/3] Expand stale bots closure band --- .../kucoin/futures/position_deal.py | 6 +- api/tests/test_kucoin_futures_stop_loss.py | 68 ++++++++++++++++++- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/api/exchange_apis/kucoin/futures/position_deal.py b/api/exchange_apis/kucoin/futures/position_deal.py index 344faf959..4a84e99ac 100644 --- a/api/exchange_apis/kucoin/futures/position_deal.py +++ b/api/exchange_apis/kucoin/futures/position_deal.py @@ -801,10 +801,10 @@ def exit(self, close_price: float, _: float | None = None) -> BotModel: and (int(time() * 1000) - self.active_bot.deal.opening_timestamp) >= 3 * 24 * 60 * 60 * 1000 ) - # Panic close only low-profit positions after 3 days. - if 0 < bot_profit < 1 and is_3_days: + # Panic close stale low-conviction positions after 3 days. + if -1 <= bot_profit < 1 and is_3_days: self.controller.update_logs( - f"Panic close triggered for {position_name} due to {'3 days elapsed' if is_3_days else 'unprofitable position'} with profit {bot_profit}. Closing position immediately.", + f"Panic close triggered for stale {position_name} position after 3 days with profit {bot_profit}. Closing position immediately.", self.active_bot, ) self.close_all() diff --git a/api/tests/test_kucoin_futures_stop_loss.py b/api/tests/test_kucoin_futures_stop_loss.py index a7947646b..7fa177611 100644 --- a/api/tests/test_kucoin_futures_stop_loss.py +++ b/api/tests/test_kucoin_futures_stop_loss.py @@ -5,7 +5,7 @@ from bots.models import BotModel, DealModel, OrderModel from exchange_apis.kucoin.futures.futures_deal import KucoinPositionDeal from exchange_apis.kucoin.futures.position_deal import PositionDeal -from pybinbot import OrderBase, OrderStatus, DealType, Position +from pybinbot import MarketType, OrderBase, OrderStatus, DealType, Position from kucoin_universal_sdk.generate.futures.order.model_add_order_req import ( AddOrderReq, ) @@ -263,6 +263,72 @@ def test_reconcile_exchange_sl_places_when_exchange_missing(): assert calls == ["cancel", "place"] +def test_exit_panic_closes_stale_mild_loser_after_three_days(monkeypatch): + deal = cast(Any, PositionDeal.__new__(PositionDeal)) + deal.price_precision = 2 + deal.active_bot = BotModel( + pair="BEATUSDTM", + market_type=MarketType.FUTURES, + position=Position.long, + stop_loss=0, + trailing=False, + take_profit=0, + deal=DealModel( + opening_price=100.0, + opening_timestamp=1_000, + ), + ) + deal.active_bot.position = Position.long + deal.controller = types.SimpleNamespace( + save=lambda bot: None, + update_logs=lambda *args, **kwargs: None, + ) + closed: list[bool] = [] + deal.close_all = lambda: closed.append(True) + + monkeypatch.setattr( + "exchange_apis.kucoin.futures.position_deal.time", + lambda: (1_000 + (4 * 24 * 60 * 60 * 1000)) / 1000, + ) + + PositionDeal.exit(deal, 99.5) + + assert closed == [True] + + +def test_exit_keeps_stale_loser_below_panic_close_band(monkeypatch): + deal = cast(Any, PositionDeal.__new__(PositionDeal)) + deal.price_precision = 2 + deal.active_bot = BotModel( + pair="BEATUSDTM", + market_type=MarketType.FUTURES, + position=Position.long, + stop_loss=0, + trailing=False, + take_profit=0, + deal=DealModel( + opening_price=100.0, + opening_timestamp=1_000, + ), + ) + deal.active_bot.position = Position.long + deal.controller = types.SimpleNamespace( + save=lambda bot: None, + update_logs=lambda *args, **kwargs: None, + ) + closed: list[bool] = [] + deal.close_all = lambda: closed.append(True) + + monkeypatch.setattr( + "exchange_apis.kucoin.futures.position_deal.time", + lambda: (1_000 + (4 * 24 * 60 * 60 * 1000)) / 1000, + ) + + PositionDeal.exit(deal, 98.9) + + assert closed == [] + + def test_reconcile_exchange_sl_skips_on_api_failure(): """API blip must not cancel/replace a possibly-still-valid SL.""" calls: list[str] = [] From 2debbd7abb0cd9959c529892a92f1dbb0f0e0779 Mon Sep 17 00:00:00 2001 From: carkod Date: Sun, 10 May 2026 01:43:43 +0100 Subject: [PATCH 2/3] Remove unecessary env vars --- api/tools/config.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api/tools/config.py b/api/tools/config.py index d753b89a2..4486a6d0b 100644 --- a/api/tools/config.py +++ b/api/tools/config.py @@ -58,7 +58,6 @@ def _validate_required_vars(self): "TZ", "SECRET_KEY", "ENV", - "BACKEND_DIRECTORY", "BACKEND_DOMAIN", "FRONTEND_DOMAIN", "POSTGRES_USER", @@ -97,10 +96,6 @@ def secret_key(self) -> str: def env(self) -> str: return self._get_required("ENV") - @property - def backend_directory(self) -> str: - return self._get_required("BACKEND_DIRECTORY") - @property def backend_domain(self) -> str: return self._get_required("BACKEND_DOMAIN") From c20d3457b2971561e9def4f95c7d9e6fbf9c9535 Mon Sep 17 00:00:00 2001 From: carkod Date: Sun, 10 May 2026 05:45:05 +0100 Subject: [PATCH 3/3] Add new Github action for staging deploy --- .github/workflows/staging-deploy.yml | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/staging-deploy.yml diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml new file mode 100644 index 000000000..e80e999e9 --- /dev/null +++ b/.github/workflows/staging-deploy.yml @@ -0,0 +1,42 @@ +name: Deploy to Staging (home server) +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + workflow_dispatch: + +env: + ACTIONS_RUNNER_DEBUG: false + +jobs: + full-stack-deploy: + runs-on: ubuntu-latest + continue-on-error: true + timeout-minutes: 20 + + steps: + - name: Connect to Tailscale + continue-on-error: true + uses: tailscale/github-action@v4 + with: + oauth-client-id: ${{ secrets.TAILSCALE_CLIENT_ID }} + oauth-secret: ${{ secrets.TAILSCALE_CLIENT_SECRET }} + tags: tag:ci + + - name: Install SSH key + continue-on-error: true + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + + echo "${{ secrets.STAGING_DEPLOY }}" > ~/.ssh/home_server_key + chmod 600 ~/.ssh/home_server_key + + ssh-keyscan -p 2222 100.64.83.67 >> ~/.ssh/known_hosts + + - name: Deploy stack + continue-on-error: true + run: | + ssh -i ~/.ssh/home_server_key \ + -p 2222 \ + "carkod@100.64.83.67" \ + 'cd /var/www/terminal.binbot.in && docker compose up --pull always -d && docker image prune -f'