feat: Notion 거래 이력 저장 모듈 구현

Made-with: Cursor
This commit is contained in:
21in7
2026-03-01 12:51:27 +09:00
parent 7a3dde2146
commit 8bbf376425
2 changed files with 114 additions and 0 deletions

72
src/database.py Normal file
View File

@@ -0,0 +1,72 @@
import json
from datetime import datetime, timezone
from notion_client import Client
from loguru import logger
class TradeRepository:
"""Notion 데이터베이스에 거래 이력을 저장하는 레포지토리."""
def __init__(self, token: str, database_id: str):
self.client = Client(auth=token)
self.database_id = database_id
def save_trade(
self,
symbol: str,
side: str,
entry_price: float,
quantity: float,
leverage: int,
signal_data: dict = None,
) -> dict:
properties = {
"Symbol": {"title": [{"text": {"content": symbol}}]},
"Side": {"select": {"name": side}},
"Entry Price": {"number": entry_price},
"Quantity": {"number": quantity},
"Leverage": {"number": leverage},
"Status": {"select": {"name": "OPEN"}},
"Signal Data": {
"rich_text": [
{"text": {"content": json.dumps(signal_data or {}, ensure_ascii=False)}}
]
},
"Opened At": {
"date": {"start": datetime.now(timezone.utc).isoformat()}
},
}
result = self.client.pages.create(
parent={"database_id": self.database_id},
properties=properties,
)
logger.info(f"거래 저장: {result['id']}")
return result
def close_trade(self, trade_id: str, exit_price: float, pnl: float) -> dict:
properties = {
"Exit Price": {"number": exit_price},
"PnL": {"number": pnl},
"Status": {"select": {"name": "CLOSED"}},
"Closed At": {
"date": {"start": datetime.now(timezone.utc).isoformat()}
},
}
result = self.client.pages.update(
page_id=trade_id,
properties=properties,
)
logger.info(f"거래 종료: {trade_id}, PnL: {pnl:.4f}")
return result
def get_open_trades(self, symbol: str) -> list[dict]:
response = self.client.databases.query(
database_id=self.database_id,
filter={
"and": [
{"property": "Symbol", "title": {"equals": symbol}},
{"property": "Status", "select": {"equals": "OPEN"}},
]
},
)
return response.get("results", [])

42
tests/test_database.py Normal file
View File

@@ -0,0 +1,42 @@
import pytest
from unittest.mock import MagicMock, patch
from src.database import TradeRepository
@pytest.fixture
def mock_repo():
with patch("src.database.Client") as mock_client_cls:
mock_client = MagicMock()
mock_client_cls.return_value = mock_client
repo = TradeRepository(token="secret_test", database_id="db_test")
repo.client = mock_client
yield repo
def test_save_trade(mock_repo):
mock_repo.client.pages.create.return_value = {
"id": "abc123",
"properties": {},
}
result = mock_repo.save_trade(
symbol="XRPUSDT",
side="LONG",
entry_price=0.5,
quantity=400.0,
leverage=10,
signal_data={"rsi": 32, "macd_hist": 0.001},
)
assert result["id"] == "abc123"
def test_close_trade(mock_repo):
mock_repo.client.pages.update.return_value = {
"id": "abc123",
"properties": {
"Status": {"select": {"name": "CLOSED"}},
},
}
result = mock_repo.close_trade(
trade_id="abc123", exit_price=0.55, pnl=20.0
)
assert result["id"] == "abc123"