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

Refactored for new official python library #10

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
**.csv
__pycache__
env
**env
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@
[Видео на YouTube](https://www.youtube.com/watch?v=QJ6yRulR_HA)

Для работы скрипта нужно установить три переменных окружения:
# Переменные окружения
```
export TINKOFF_TOKEN=some_tinkoff_token
export TINKOFF_BROKER_ACCOUNT=some_broker_account
export TINKOFF_ACCOUNT_STARTED=01.06.2020
```
Поддерживается .env файл.

Здесь `TINKOFF_TOKEN` это токен Тиньков инвестиций,
`TINKOFF_BROKER_ACCOUNT` это ID портфеля в Тинькове (его можно получить
в `tinvest.UserApi(client).accounts_get().parse_json().payload`),
`TINKOFF_ACCOUNT_STARTED` это дата открытия портфеля в формате дд.мм.гггг,
от этой даты будут считаться пополнения.
Здесь `TINKOFF_TOKEN` это токен Тиньков инвестиций.

Использование:
# Использование
Для запуска проекта нужно активировать окружение, установить зависимости и запустить скрипт `go.py`.

## Poetry
```
poetry shell
poetry install
python go.py
```

## PIP
```
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python go.py
```
130 changes: 85 additions & 45 deletions go.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,100 @@
from datetime import datetime
from decimal import Decimal
import locale
import os

import tinvest
from datetime import datetime
from dotenv import load_dotenv
from tinkoff.invest import Client, GetOperationsByCursorRequest, OperationType
from pprint import pprint
from loguru import logger


load_dotenv()
token = os.environ["TINKOFF_TOKEN"]

OP_PAY_IN = OperationType(1) # Пополнение брокерского счета
OP_OUT = OperationType(9) # Вывод денежных средств

class TinAnal:
def __init__(self) -> None:
self.actual_account_names = ["ETF", "Долгосрочный инвестор - Россия", "Bonds", "Копилка"]
self.account_ids = self._get_accounts()

from tinkoffapi import TinkoffApi
def _get_accounts(self) -> list:
with Client(token) as client:
accounts = client.users.get_accounts().accounts
actual_accounts = [acc for acc in accounts if acc.name in self.actual_account_names]
logger.info(f"My actual accounts:")
# pprint(actual_accounts)
return [acc.id for acc in actual_accounts]

def get_account_pay_in(self, account_id, start, end):
with Client(token) as client:
req = GetOperationsByCursorRequest(
account_id=account_id,
operation_types=[OP_PAY_IN],
from_=start,
to=end
)
operations = client.operations.get_operations_by_cursor(req)

sum = 0
for op in operations.items:
sum += op.payment.units

# Токен Тиньков Инвестиций
TOKEN = os.getenv('TINKOFF_TOKEN')
# Идентификатор портфеля в Тиньков инвестициях, его можно получить так:
# tinvest.UserApi(client).accounts_get().parse_json().payload
BROKER_ACCOUNT_ID = os.getenv('TINKOFF_BROKER_ACCOUNT')
# Дата, от которой будут получены пополнения портфеля
BROKER_ACCOUNT_STARTED_AT = datetime.strptime(os.getenv('TINKOFF_ACCOUNT_STARTED'),
'%d.%m.%Y')
return sum

locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')
api = TinkoffApi(api_token=TOKEN, broker_account_id=BROKER_ACCOUNT_ID)
usd_course = api.get_usd_course()
print(f"Текущий курс доллара в брокере: {usd_course} руб")
def _get_operations(self, account_id, start, end):
start = datetime.strptime(start, "%Y-%m-%d")
end = datetime.strptime(end, "%Y-%m-%d")
with Client(token) as client:
req = GetOperationsByCursorRequest(
account_id=account_id,
from_=start,
to=end
)
operations = client.operations.get_operations_by_cursor(req)

logger.info("operations:")
pprint([(op_it.type, op_it.description, op_it.date) for op_it in operations.items])
sum = 0
for op in operations.items:
sum += op.payment.units

def get_portfolio_sum() -> int:
"""Возвращает текущую стоимость портфеля в рублях без учета
просто лежащих на аккаунте рублей в деньгах"""
positions = api.get_portfolio_positions()
return sum

portfolio_sum = Decimal('0')
for position in positions:
current_ticker_cost = (Decimal(str(position.balance))
* Decimal(str(position.average_position_price.value))
+ Decimal(str(position.expected_yield.value)))
if position.average_position_price.currency.name == "usd":
current_ticker_cost *= usd_course
portfolio_sum += current_ticker_cost
return int(portfolio_sum)
def get_sum_pay_in(self, start, end):
all_acc_pay_in = 0
for account_id in self.account_ids:
all_acc_pay_in += self.get_account_pay_in(account_id, start, end)

return all_acc_pay_in

def get_sum_pay_in() -> int:
"""Возвращает сумму всех пополнений в рублях"""
operations = api.get_all_operations(BROKER_ACCOUNT_STARTED_AT)

sum_pay_in = Decimal('0')
for operation in operations:
if operation.operation_type.value == "PayIn":
sum_pay_in += Decimal(str(operation.payment))
return int(sum_pay_in)
def get_portfolio_sum(self):
total_sum = 0
with Client(token) as client:
for account_id in self.account_ids:
portfolio = client.operations.get_portfolio(account_id=account_id)
total_sum += portfolio.total_amount_portfolio.units
return total_sum


def analyze(self, start_date="", end_date=""):
start_date_timestamp = datetime.strptime(start_date, "%Y-%m-%d")
end_date_timestamp = datetime.strptime(end_date, "%Y-%m-%d")

portfolio_sum = self.get_portfolio_sum()
sum_pay_in = self.get_sum_pay_in(start_date_timestamp, end_date_timestamp)

# profit_in_rub = portfolio_sum - sum_pay_in
# profit_in_percent = 100 * round(profit_in_rub / sum_pay_in, 4)

print(f"За период {start_date} - {end_date}:\n-------------------------\n"
f"Пополнения: {sum_pay_in:n} руб\n"
f"Текущая рублёвая стоимость портфеля: {portfolio_sum:n} руб\n")


if __name__ == "__main__":
portfolio_sum = get_portfolio_sum()
sum_pay_in = get_sum_pay_in()
profit_in_rub = portfolio_sum - sum_pay_in
profit_in_percent = 100 * round(profit_in_rub / sum_pay_in, 4)
print(f"Пополнения: {sum_pay_in:n} руб\n"
f"Текущая рублёвая стоимость портфеля: {portfolio_sum:n} руб\n"
f"Рублёвая прибыль: {profit_in_rub:n} руб ({profit_in_percent:n}%)")
analytics = TinAnal()

# analytics._get_operations(analytics.account_ids[3], "2024-06-05", "2024-06-08")
analytics.analyze("2024-05-01", "2024-05-31")
Loading