""" Pruebas de la prima (prima.py): cuánto se aleja del mercado de ese día lo que se pagó o cobró por el bitcoin, y de poner el importe de verdad a una compra. python3 -m unittest discover -s pruebas -v """ from __future__ import annotations import sys import tempfile import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from cartera import prima, spot_btc # noqa: E402 from cartera.datos import Datos, escribir, leer # noqa: E402 from cartera.operaciones import Cartera, ErrorOperacion # noqa: E402 from cartera.servidor import App # noqa: E402 DIA = "2024-03-10" class ConCartera(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.carpeta = Path(self.tmp.name) / "datos" self.carpeta.mkdir() escribir(self.carpeta, Datos( [{"id": "C1", "nombre": "Bitcoin", "tipo": "Cripto", "codigo": "bitcoin", "unidad": "BTC", "fecha_inicio": "2020-01-01", "estado": "abierta"}, {"id": "F1", "nombre": "Fondo", "tipo": "Fondo", "codigo": "ES0000000001", "unidad": "part.", "fecha_inicio": "2020-01-01", "estado": "abierta"}], [], [], [])) self.c = Cartera(self.carpeta) self.addCleanup(self.c.cerrar) self.cierre = spot_btc.precio(DIA)[0] def compra(self, veces: float, **extra) -> dict: """Una compra de 0,1 BTC pagada a «veces» el cierre de ese día.""" return self.c.guardar_movimiento({"activo": "C1", "tipo": "Compra", "fecha": DIA, "cantidad": 0.1, "importe": round(0.1 * self.cierre * veces, 2), **extra}) def primas(self) -> dict: d = self.c.datos return prima.de_movimientos(d.vivos("activos"), d.vivos("movimientos"), d.vivos("precios")) class TestPrima(ConCartera): def test_una_compra_p2p_normal_lleva_su_prima_y_no_avisa(self): m = self.compra(1.06) p = self.primas()[m["id"]] self.assertAlmostEqual(p["prima"], 0.06, places=3) self.assertEqual((p["ref"], p["dia"], p["lejos"]), (self.cierre, DIA, False)) def test_avisa_de_lo_que_queda_lejos_del_mercado(self): cara, barata, justa = self.compra(1.2), self.compra(0.9), self.compra(0.97) p = self.primas() self.assertEqual([p[m["id"]]["lejos"] for m in (cara, barata, justa)], [True, True, False]) def test_en_una_venta_lo_raro_es_al_reves(self): self.compra(1.0) def venta(veces): return self.c.guardar_movimiento({"activo": "C1", "tipo": "Venta", "fecha": DIA, "cantidad": 0.01, "importe": round(0.01 * self.cierre * veces, 2)}) regalada, cara, normal = venta(0.8), venta(1.1), venta(0.96) p = self.primas() self.assertEqual([p[m["id"]]["lejos"] for m in (regalada, cara, normal)], [True, True, False]) def test_solo_mira_compras_y_ventas_de_bitcoin_con_importe(self): self.compra(1.0) self.c.guardar_movimiento({"activo": "C1", "tipo": "Mineria", "fecha": DIA, "cantidad": 0.01}) self.c.guardar_movimiento({"activo": "F1", "tipo": "Compra", "fecha": DIA, "cantidad": 10, "importe": 1000}) self.assertEqual(len(self.primas()), 1) def test_sin_un_cierre_cercano_no_se_inventa_la_prima(self): m = self.c.guardar_movimiento({"activo": "C1", "tipo": "Compra", "fecha": "2010-06-01", "cantidad": 1, "importe": 0.5}) self.assertNotIn(m["id"], self.primas()) class TestImporteDeVerdad(ConCartera): def test_poner_el_importe_cambia_el_precio_no_la_cantidad_y_deja_de_ser_estimada(self): m = self.compra(1.0, estimado=True, notas="Compra · del nodo abc…") self.c.enlazar_txid(m["id"], "ab" * 32) r = self.c.poner_importe(m["id"], 3500.40) self.assertEqual((r["importe"], r["cantidad"], r["estimado"]), (3500.40, 0.1, False)) self.assertAlmostEqual(r["precio"], 35004.0) self.assertEqual((r["notas"], r["txid"]), ("Compra · del nodo abc…", "ab" * 32)) # lo demás, intacto self.assertEqual(leer(self.carpeta).movimientos[0]["importe"], 3500.40) # y queda guardado def test_solo_vale_para_compras_y_ventas_con_un_importe_positivo(self): m = self.compra(1.0) mineria = self.c.guardar_movimiento({"activo": "C1", "tipo": "Mineria", "fecha": DIA, "cantidad": 0.01}) for mid, importe in ((m["id"], 0), (m["id"], ""), (m["id"], "mucho"), (mineria["id"], 100)): with self.assertRaises(ErrorOperacion): self.c.poner_importe(mid, importe) def test_una_cifra_rara_pero_buena_se_marca_y_se_puede_desmarcar(self): m = self.compra(1.3) self.assertEqual(self.c.revisar_prima([m["id"]])["cambiadas"], 1) self.assertTrue(leer(self.carpeta).movimientos[0]["prima_ok"]) self.c.revisar_prima([m["id"]], ok=False) self.assertNotIn("prima_ok", leer(self.carpeta).movimientos[0]) def test_la_pantalla_recibe_las_primas_con_el_estado(self): m = self.compra(1.3) estado = App(self.c).estado() self.assertTrue(estado["primas"][m["id"]]["lejos"]) if __name__ == "__main__": unittest.main()