Compare commits

..

4 Commits

5 changed files with 58 additions and 4 deletions

30
.github/workflows/rebalance.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Weekly Portfolio Rebalance
on:
# 1. Запуск по расписанию (каждый понедельник в 10:30 МСК)
schedule:
- cron: '30 7 * * 1' # Время в UTC (7:30 UTC = 10:30 МСК)
# 2. Возможность запустить вручную кнопкой в интерфейсе GitHub
workflow_dispatch:
jobs:
rebalance:
runs-on: ubuntu-latest
environment: tinvest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Set up Python
run: uv python install 3.13
- name: Run Rebalance Bot
env:
# Передаем секреты в переменные окружения скрипта
TINVEST_TOKEN: ${{ secrets.TINVEST_TOKEN }}
run: uv run app/main.py

View File

@@ -17,4 +17,4 @@ TARGET_WEIGHTS = {
"ROSN": Decimal("0.05"), "ROSN": Decimal("0.05"),
} }
CORRIDOR = Decimal("0.02") # 3% коридор отклонения от целевой доли CORRIDOR = Decimal("0.02") # 2% коридор отклонения от целевой доли

21
app/load_config.py Normal file
View File

@@ -0,0 +1,21 @@
import yaml
from decimal import Decimal
def load_config(config_path: str) -> dict:
with open(config_path, "r") as file:
data = yaml.safe_load(file)
target_weights = {
ticker: Decimal(str(weight)) for ticker, weight in data["portfolio"].items
}
config = {
"account_id": data["account"]["id"],
"is_sandbox": data["account"]["is_sandbox"],
"corridor": Decimal(str(data["settings"]["corridor"])),
"dry_run": data["settings"]["dry_run"],
"target_weights": target_weights,
}
return config

View File

@@ -10,13 +10,13 @@ load_dotenv()
def main(): def main():
with SandboxClient(token=os.getenv("TINVEST_TOKEN")) as client: # type: ignore with Client(token=os.getenv("TINVEST_TOKEN")) as client: # type: ignore
bot = RebalanceBot( bot = RebalanceBot(
client=client, client=client,
account_id="bb29bb79-8cf1-42ba-843f-47ef76c5b7c0", account_id="2235046505",
target_weights=TARGET_WEIGHTS, target_weights=TARGET_WEIGHTS,
corridor=CORRIDOR, corridor=CORRIDOR,
dry_run=True, dry_run=False,
) )
plan = bot.calculate_rebalance(bot.fetch_portfolio()) plan = bot.calculate_rebalance(bot.fetch_portfolio())
@@ -30,3 +30,5 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()
# with Client(token=os.getenv("TINVEST_TOKEN")) as client:
# print(client.users.get_accounts())

View File

@@ -71,6 +71,7 @@ class RebalanceBot:
if lots != 0: if lots != 0:
plan.append( plan.append(
{ {
"figi": pos.figi,
"ticker": ticker, "ticker": ticker,
"uid": uid, "uid": uid,
"action": "BUY" if lots > 0 else "SELL", "action": "BUY" if lots > 0 else "SELL",