114 lines
5.2 KiB
Python
114 lines
5.2 KiB
Python
"""
|
|
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()
|