3. Qué hacer con una posición abierta cuando el sistema se cae
Nivel 11: Cuando falla
Son las 15:42. Tienes cuatro posiciones abiertas, una orden límite viva en el mercado y otra enviada hace ocho segundos de la que aún no tienes confirmación. El proceso muere. A las 16:05 vuelve a estar arriba. Este módulo trata de esos veintitrés minutos y, sobre todo, de la primera decisión que toma el sistema al volver, que es donde se pierde el dinero de verdad.
Lo que no hay que hacer: arrancar y creerse el disco
El arranque ingenuo es leer el fichero de estado, ver que dice cuatro posiciones y una orden viva, cargarlo en memoria y seguir operando desde ahí. Es lo que hace casi todo el mundo la primera vez y está mal por una razón concreta: lo que guardaste en disco es tu última intención, no un hecho del mundo. Entre el último guardado y la muerte del proceso cabe una ejecución completa, una parcial, una cancelación del bróker o el relleno de esa orden de la que no tenías confirmación.
El bróker es la fuente de verdad; tu fichero es lo que tú creías. Y hay un caso especialmente traicionero: la orden enviada sin confirmar. Si asumes que no salió, puedes acabar con doble posición. Si asumes que salió, puedes quedarte esperando una ejecución que nunca ocurrió.
El protocolo de arranque con posición abierta
Se arranca siempre en modo de solo lectura y se compara antes de tocar nada:
def arranque_seguro(broker, estado, politica):
real_pos = broker.posiciones()
real_ord = broker.ordenes_abiertas()
intencion = estado.ultima_intencion()
diffs = comparar(intencion, real_pos, real_ord)
if not diffs:
return 'coincide: reanudar normal'
if politica.puede_quedarse_quieta and not politica.autocierre:
estado.freno('divergencia al arrancar: %r' % diffs)
return 'parado: requiere intervencion humana'
for o in real_ord:
if not estado.reconoce(o.id):
estado.freno('orden desconocida %s' % o.id)
return 'parado: orden no reconocida'
return politica.resolver(diffs)Tres detalles. El sistema no cancela ni cierra nada por su cuenta antes de haber comparado. Una orden abierta que tu registro no reconoce nunca se cancela a ciegas, porque puede ser de otra estrategia, de otra cuenta o de una mano humana. Y cuando la divergencia no se explica, la salida no es una operación: es pararse y llamar a alguien.
Estrategias que pueden quedarse quietas y estrategias que no
Ahora la pregunta que ordena todo lo demás: si el proceso muere ahora y nadie lo toca en veinticuatro horas, ¿cuál es la peor pérdida posible?
Hay estrategias donde la respuesta es una molestia. Una rotación mensual de acciones al contado, sin apalancamiento y diversificada, puede pasar un día sin supervisión: lo que arriesga estando quieta es el riesgo de mercado normal, el mismo que asume quien se va de vacaciones. Esa puede quedarse quieta, y su modo seguro es no hacer nada.
Y hay estrategias donde la respuesta te quita el sueño. Cualquier cosa apalancada, la venta de opciones descubiertas, el intradía concentrado, todo lo que dependa de una salida programada para acotar la pérdida. Ahí el perfil de riesgo que mediste presupone que hay alguien vigilando, y estar quieto no es neutral: es una posición nueva que nunca decidiste tomar.
Esta clasificación se hace antes, en frío, y se escribe en la configuración junto con la política de arranque. En caliente, a las 16:05, con una posición abierta, nadie decide bien si cerrar o mantener. Ese día no decides qué hacer: ejecutas lo que ya habías decidido.
Órdenes de protección en el bróker: la red que sobrevive a tu servidor
Si tu estrategia no puede quedarse quieta, la única red que funciona es la que no vive en tu máquina. Una orden de protección colocada en el bróker sigue ahí aunque muera tu proceso y arda el centro de datos entero. No sale gratis, y conviene saber el precio antes de pagarlo:
- Ejecuta en el peor momento. Un stop de mercado se dispara justo cuando hay un vacío de liquidez, y sales muy lejos del nivel que escribiste.
- Te expone a las mechas. Un pico de un segundo, incluso erróneo, lo toca y te saca de una posición que la estrategia habría mantenido.
- Es un segundo estado que se desincroniza. Cada vez que cambias la posición hay que cambiar la protección.
- Depende del bróker al desconectar. Algunos mercados cancelan automáticamente las órdenes al perder la conexión, justo lo contrario de lo que quieres aquí. Hay que saber cuál de los dos tiene el tuyo, y saberlo antes, no el día del susto.
Por eso la protección se coloca en el mismo paso en que se abre la posición, no en un ciclo posterior, y la reconciliación comprueba las dos direcciones:
def abrir_con_red(broker, estado, simbolo, cantidad, stop):
orden = broker.mercado(simbolo, cantidad)
broker.esperar_ejecucion(orden)
proteccion = broker.stop(simbolo, -cantidad, stop)
estado.vincular(orden.id, proteccion.id)
return proteccion
def protecciones_huerfanas(broker):
pos = {p.simbolo: p.cantidad for p in broker.posiciones()}
return [o for o in broker.ordenes_abiertas()
if o.tipo == 'stop' and pos.get(o.simbolo, 0) == 0]Una protección huérfana no es una red: es una orden que abrirá una posición contraria en cuanto el precio la toque.
Escenario trabajado
Lo que sigue es un ejemplo construido para el curso, no un incidente real. Sistema intradía, patrimonio de 100.000 euros, tres posiciones largas por 60.000 en total y una orden de venta límite viva. El proceso muere a las 15:42 por falta de memoria. El supervisor lo relanza a las 15:44.
Sin protocolo de arranque, el sistema lee el estado en disco, no ve que la orden límite se ejecutó a las 15:43 y vuelve a mandar la misma venta: acaba corto de un valor que nunca quiso vender dos veces, y lo descubre al cierre. Con protocolo, el arranque pide posiciones al bróker, ve que una línea ya no está, no encuentra explicación en la intención registrada, activa el freno y manda un aviso. Coste del segundo camino: veinte minutos sin operar y una llamada. Coste del primero: una posición corta no deseada, más lo que el mercado haga con ella hasta que alguien mire.