Spirit escribió:Hay gente que no entiende bien el alcance que pueden tener ciertos problemas. En una ocasión tuvimos que programar una rutina para sorteos de vivienda protegida. Si a los que me contrataron les hubiera dado las respuestas que se están dando aquí les hubiera entrado la risa y por suspuesto no me hubieran contratado.
Si en uno cualquiera de los múltiples sorteos realizados con ese programa, se hubiera producido el más mínimo error y los sistemas de vigilancia no lo hubieran detectado y reparado hoy en día tendría un grave problema, los medios de comunicación la hubieran liado gorda, la oposición hubiera echado más leña al fuego y alguna cabeza gorda hubiera rodado.
Es increible con la vanalidad que hablan algunos de cuestiones que reálmente si tienen importancia. evidéntemente si un tipo opera acciones de las matildes sin palanca alguna y con operativa de tipo swing de no más de una operación al mes, todo esto le parecerá ciencia-fición.
Si planteo la pregunta o debate, es porque estoy midiendo la posibilidad de automatizar sistemas full-time que me funcionan de forma discreccional, pero son inviables e insufribles de mantener operativos sin ayudas automáticas, pero al ser full-time y correr en cuentas que permiten apalancamientos altos, aunque no se usen estos, el riesgo de ruina en caso de problemas es muy elevado. Si al final concluyo que no merece la pena tomar ese riesgo, o que no puedo minimizarlo lo suficiente, o sus costes son muy elevados, pues no lo implementaré. Pero ¿Por qué voy a desechar la idea de implementar unos sistemas que me están funcionando muy bien? Primero tendré que ver si son viables tecnológicamente hablando y luego valorar todas las posibilidades.
Por eso, me gustaría ver más respuestas del tipo de las de CLS. Es decir, no hace falta que nadie aporte soluciones, que eso es relativamente sencillo, lo jodido es conocer todos los posibles problemas que pueden aparecer. Si lo que ha dicho CLS lo paso por alto, puedo estar 3 años sin un problema, pero un día por arte de magia levantarme con la cuenta arruinada. No se si se entiende ahora mejor el planteamiento del debate que propongo.
Se entiende, pero cuando sólo el 1% (u otro porcentaje muy bajo) de todo el código que interviene en la ejecución de tu estrategia, es tuyo, pues tienes que pensar que habrá problemas, tarde o temprano. Hay que hacer todo lo posible para detectar estos problemas lo antes posible.
En el caso de cls, el fallo fué provocado por un "error" en la herramienta, no en su código. Claro que la solución de bloquear todo el entorno hasta que una orden haya sido ejecutada, pues puede no gustar a todo el mundo.
Problemas tan especiales no se me ocurren, pero si quieres vigilar los saldos de tus cuentas, ejecución de órdenes... puedes hacer que un programa, independiente de todo el entorno de ejcución de órdenes, se conecte a la web del broker (o use un API independiente) y monitorice el estado de las cuentas, órdenes...
No es muy complicado, basta conectarse a la web, botón derecho "Ver código fuente".
Este es el código en c# (primera versión a matacaballo) para conectarse a la web de Interdin y conocer el saldo de una cuenta.
Obviamente, cuando me cambien el diseño de la web, pues un buen susto
public static void LeerSaldoCuenta(int IDCuenta)
{
string sql = "SELECT Usuario, Clave, Numero, Saldo, Disponible"
+ " FROM Cuenta"
+ " WHERE IDCuenta = " + IDCuenta;
DataRow dr = Util.getDataTable(sql).Rows[0];
ConectorInterdin.EstablecerDatos(dr["Usuario"].ToString(),
dr["Clave"].ToString(),
dr["Numero"].ToString());
string res = ConectorInterdin.LeerGet("
https://www.interdinfuturos.com/Broker/MiCuenta.asp?nc=" + dr["Numero"].ToString());
double saldo = 0;
double disponible = 0;
string parcial = "";
//<td class="textonegro">
//Saldo en Tiempo Real: <strong> 99999.99 €
//<br>
//</strong>Disponible para operar: <strong>99999.9 €</strong>
//<br>
//</td>
for (int prueba = 0; prueba < 3; ++prueba)
{
if (res.IndexOf("Saldo en Tiempo Real: <strong> ") <= 0) // Si res está en blanco también.
{
ConectorInterdin.CerrarConexion();
res = ConectorInterdin.LeerGet("
https://www.interdinfuturos.com/Broker/MiCuenta.asp?nc=" + dr["Numero"].ToString());
}
else
{
break;
}
}
parcial = Util.Extraer(res, "Saldo en Tiempo Real: <strong> ", " €");
saldo = double.Parse(parcial.Replace(",", "").Replace('.', ','));
parcial = Util.Extraer(res, "Disponible para operar: <strong>", " €");
disponible = double.Parse(parcial.Replace(",", "").Replace('.', ','));
if (saldo > 0 && disponible > 0)
{
if ((double)dr["Saldo"] != saldo || (double)dr["Disponible"] != disponible)
{
Util.executeSQL("UPDATE Cuenta"
+ " Set Saldo = " + Util.SQLNumero(saldo)
+ ", Disponible = " + Util.SQLNumero(disponible)
+ " WHERE IDCuenta = " + IDCuenta);
}
}
else
{
throw new Exception("Error al leer el estado de la cuenta.");
}
}
Siendo ConectorInterdin:
class ConectorInterdin
{
private static object lockConector = new object();
private static CookieAwareWebClient cnx = null;
private static string Usuario = "";
private static string Clave = "";
private static string Numero = "";
private static Random rnd = new Random(Environment.TickCount);
public static string NumeroCuentaActual
{
get
{
return Numero;
}
}
public static void EstablecerDatos(string UsuarioActual, string ClaveActual, string NumeroActual)
{
lock (lockConector)
{
if (Numero != "" && Numero != NumeroActual)
{
CerrarConexion();
}
Usuario = UsuarioActual;
Clave = ClaveActual;
Numero = NumeroActual;
}
}
private static void Tiempo()
{
System.Threading.Thread.Sleep(rnd.Next(5, 100));
}
private static bool IniciandoConexion = false;
private static bool IniciarConexion()
{
NameValueCollection parametros = new NameValueCollection();
string NC = "";
#if (DEBUG)
System.Diagnostics.Debug.Print(DateTime.Now.ToLongTimeString() + " iniciar conexion.");
#endif
if (IniciandoConexion)
{
throw new Exception("Error en llamada a IniciarConexion");
}
IniciandoConexion = true;
cnx = new CookieAwareWebClient();
cnx.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
cnx.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
parametros.Add("Nombre", Usuario);
parametros.Add("Clave", Clave);
parametros.Add("ok", "OK");
NC = Util.Extraer(LeerPost("
https://www.interdinfuturos.com/Broker/Verificacion.asp", parametros), "MiCuenta.asp?nc=", "\"");
IniciandoConexion = false;
if (NC != Numero)
{
throw new Exception("Error la cuenta es incorrecta.");
}
#if (DEBUG)
System.Diagnostics.Debug.Print(DateTime.Now.ToLongTimeString() + " conexion iniciada.");
#endif
return true;
}
public static void CerrarConexion()
{
#if (DEBUG)
System.Diagnostics.Debug.Print(DateTime.Now.ToLongTimeString() + " cerrar conexion.");
#endif
lock (lockConector)
{
try
{
if (cnx != null)
{
Tiempo();
cnx.OpenRead("
https://www.interdinfuturos.com/Broker/Desconectar.asp");
}
}
catch
{
}
if (cnx != null)
{
cnx.Dispose();
cnx = null;
}
}
GC.Collect();
}
public static string LeerGet(string URL)
{
string res = "";
lock (lockConector)
{
if (cnx == null)
{
IniciarConexion();
}
for (int intento = 0; intento < 4; ++intento)
{
try
{
Tiempo();
res = cnx.DownloadString(URL);
break;
}
catch (Exception exp)
{
if (intento == 3)
{
throw exp;
}
}
}
}
return res;
}
public static string LeerPost(string URL, NameValueCollection Parametros)
{
byte[] responseBytes = null;
lock (lockConector)
{
if (cnx == null)
{
IniciarConexion();
}
for (int intento = 0; intento < 4; ++intento)
{
try
{
Tiempo();
responseBytes = cnx.UploadValues(URL,
"POST", Parametros);
break;
}
catch (Exception exp)
{
if (!IniciandoConexion)
{
cnx.Dispose();
cnx = null;
}
if (intento == 3)
{
throw exp;
}
}
}
}
return System.Text.ASCIIEncoding.ASCII.GetString(responseBytes);
}
}
class CookieAwareWebClient : WebClient
{
private CookieContainer m_container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = m_container;
(request as HttpWebRequest).KeepAlive = true;
}
return request;
}
}