Files
xiaobai-review/tests/test_trade_journal.py
T

91 lines
3.4 KiB
Python

from __future__ import annotations
import tempfile
import unittest
from pathlib import Path
from database import ReviewDatabase
from backend.features.review.trade_journal import TradeJournalService
class TradeJournalTests(unittest.TestCase):
def setUp(self) -> None:
self.temp = tempfile.TemporaryDirectory()
self.database = ReviewDatabase(Path(self.temp.name) / "review.db")
self.owner = self.database.create_user("trade_owner", "salt", "hash")
self.other = self.database.create_user("trade_other", "salt", "hash")
self.service = TradeJournalService(self.database)
def tearDown(self) -> None:
self.temp.cleanup()
@staticmethod
def payload(**overrides):
data = {
"trade_date": "2026-07-22",
"code": "002141",
"name": "贤丰控股",
"action": "buy",
"price": 10.25,
"quantity": 1000,
"position_pct": 20,
"pnl_amount": "",
"pnl_pct": "",
"thesis": "修复期低吸",
"execution": "按计划成交",
"emotion": "calm",
"tags": "计划内,低吸",
}
data.update(overrides)
return data
def test_unrealized_entry_does_not_enter_win_rate(self):
self.service.save(self.owner["id"], self.payload())
result = self.service.list_entries(self.owner["id"])
self.assertEqual(result["summary"]["total"], 1)
self.assertEqual(result["summary"]["realized"], 0)
self.assertIsNone(result["summary"]["win_rate"])
self.assertEqual(result["items"][0]["tags"], ["计划内", "低吸"])
def test_realized_entries_build_summary(self):
self.service.save(
self.owner["id"], self.payload(action="sell", pnl_amount=500, pnl_pct=5)
)
self.service.save(
self.owner["id"],
self.payload(code="600000", name="浦发银行", action="sell", pnl_amount=-200, pnl_pct=-2, position_pct=40),
)
result = self.service.list_entries(self.owner["id"])
self.assertEqual(result["summary"]["realized"], 2)
self.assertEqual(result["summary"]["win_rate"], 50.0)
self.assertEqual(result["summary"]["pnl_amount"], 300.0)
self.assertEqual(result["summary"]["average_position"], 30.0)
def test_update_and_delete_require_ownership(self):
trade_id = self.service.save(self.owner["id"], self.payload())
with self.assertRaises(ValueError):
self.service.save(
self.other["id"], self.payload(id=trade_id, thesis="越权修改")
)
self.assertFalse(self.database.delete_trade_entry(self.other["id"], trade_id))
self.service.save(
self.owner["id"], self.payload(id=trade_id, thesis="复盘后修订")
)
self.assertEqual(
self.service.list_entries(self.owner["id"])["items"][0]["thesis"],
"复盘后修订",
)
self.assertTrue(self.database.delete_trade_entry(self.owner["id"], trade_id))
self.assertEqual(self.service.list_entries(self.owner["id"])["summary"]["total"], 0)
def test_entries_are_isolated_between_accounts(self):
self.service.save(self.owner["id"], self.payload())
self.assertEqual(self.service.list_entries(self.other["id"])["items"], [])
if __name__ == "__main__":
unittest.main()