Jugar JavaScript con los viejos -- Crear un compañero de compras y ventas [7] herramientas útiles para saber por qué es útil!

El autor:Un sueño pequeño., Creado: 2017-03-16 12:29:51, Actualizado: 2017-10-11 10:37:54

¡Las herramientas útiles deben saber por qué son útiles!

Es un placer escribir estrategias durante la semana, y las ideas de todo tipo aparecen rápidamente en el editor, tal vez sea tu próxima copa sagrada, ¡es emocionante! El único que afecta a esta pasión es el manejo de la lógica de compra y venta de los sistemas de estrategia de trading, que es esencial para el manejo de este módulo de trading, aunque es un poco aburrido y la lógica es más compleja.

  • Es bueno tener un módulo bien escrito que se pueda usar directamente (los artículos anteriores lo han usado), pero además de usarlo y aprender cómo funciona, he comentado el código:

¿Qué es eso? Interval Intervalo de repetición fallido (millisegundos) Tipo numérico (número) 500 SlideTick Número de puntos del precio deslizante (número entero) Tipo numérico (número) 1 RiskControl activa el control del viento Tipo de bol (true/false) falso MaxTrade@RiskControl Número máximo de transacciones en un día laborable Tipo numérico (numero) 50 MaxTradeAmount@RiskControl Un máximo de una cantidad de dinero por cuenta (número) 1000 ¿Qué es eso?

var __orderCount = 0 // Registra el siguiente número de unidades del día laborable actual var __orderDay = 0 // registra la fecha del día de trabajo actual

función CanTrade ((tradeAmount) { // módulo de control de riesgos, Parámetros: número de operaciones if (!RiskControl) { // Por defecto no se activa el módulo de control de viento, si no se activa, la función CanTrade devuelve true No es cierto. ¿Por qué no? if (typeof(tradeAmount) == number && tradeAmount > MaxTradeAmount) { // Introducir el parámetro tradeAmount como tipo numérico, y el volumen de envío es mayor que el volumen máximo de envío establecido en el parámetro de la plantilla Log ((el módulo de control de tormentas limita, excede el máximo volumen de descarga, MaxTradeAmount, #ff0000 @); // Exporta el mensaje de sugerencia, interrumpe la ejecución. lanzamiento interruptor ejecutar el lanzamiento ¿Qué es lo que está pasando? ¿Por qué no? var nowDay = new Date (().getDate ((); // Obtiene la fecha actual if (nowDay!= __orderDay) { // getDate() Devuelve un día de un mes (1 ~ 31) desde el objeto Date. __orderDay = nowDay; // __orderDay La variable global registra la fecha en que el módulo de control de viento fue activado por primera vez. __orderCount = 0; // actualiza la variable __orderDay y vuelve a colocar la variable __orderCount ¿Por qué no? __orderCount++; // Variable global __orderCount El siguiente número único, autocompletado. if (__orderCount > MaxTrade) { // determina si el número máximo de operaciones en un día es mayor que el establecido por el parámetro Log ((restricción del módulo de control de tormentas, no se puede negociar, excede el número máximo de unidades de tormentas, MaxTrade, #ff0000 @); // excede, transmite el mensaje de sugerencia, interrumpe la ejecución. lanzamiento interruptor ejecutar el lanzamiento ¿Qué es lo que está pasando? ¿Por qué no? return true; // ninguna de las condiciones anteriores se ha activado, devuelve true, es decir, se puede negociar. ¿Por qué no?

function init ((() { // Función de inicialización de la plantilla, que se ejecuta primero cuando se carga la plantilla. if (typeof ((SlideTick) === undefined) { // comprueba si SlideTick no está definido. SlideTick = 1; // configuración El valor predeterminado es 1 } else { // Se analiza una cadena convertida a un valor numérico, aunque puede causar errores si es una cadena que comienza con un carácter no numérico y devuelve NaN En el caso de las personas que se encuentran en una situación similar a la de las personas que se encuentran en una situación similar a la de las personas que se encuentran en una situación similar a la de las personas que se encuentran en una situación similar. ¿Por qué no? Log (la cartera de transacciones de commodities se ha cargado con éxito); ¿Por qué no?

function GetPosition ((e, contractType, direction, positions) { // Combina un contrato con posiciones pasadas y actuales en la misma dirección, con los siguientes parámetros: objeto de intercambio, tipo de contrato, dirección, datos de tenencia devueltos por la API ((vacío)
var allCost = 0; // ContractType Contract in direction Total de los fondos gastados, sin multiplicar por un solo contrato (porque el conjunto puede ser contratado) var allAmount = 0; // Número total de manos del contrato var allProfit = 0; // ganancias y pérdidas totales var allFrozen = 0; // Número total de congelaciones var pos Margen = 0; // Contratos de tenencia Apalancamiento if (typeof(positions) === undefinedᅢ!positions) { // Si el parámetro no transmite información de almacenamiento devuelta a la API positions = _C ((e.GetPosition); // donde se llama a la API para obtener información de almacenamiento. ¿Qué quieres decir? para (var i = 0; i < positions.length; i++) { // se extiende por el conjunto de información almacenada. if (positions[i].ContractType == contractType && // Código de contrato de la información de tenencia del índice actual == Código de contrato especificado por el parámetro ((contractType)) y la dirección es igual a la dirección en la que se transmite el parámetro ((direction)) en la posición actual o en la posición anterior (positions[i].Type == PD_LONG de posiciones[i].Type == PD_LONG_YD) && direction == PD_LONG de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_LONG de posiciones[i].Type == PD_LONG_YD de posiciones[i].Type == PD_LONG_YD de posiciones[i].Type == PD_LONG_YD de posiciones[i].Type == PD_LONG_YD de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_SHORT de posiciones[i].Type == PD_SHORT de posiciones[i] y dirección == PD_SHORT de dirección]]) ) { // cumple con el requisito de ejecutar el bloque if Pos Margin = positions[i].MarginLevel; // Obtener el valor del apalancamiento Asignar un valor a pos Margin allCost += (positions[i].Price * positions[i].Amount); // Total de los gastos (cuantidad de contratos vendidos, precio de tenencia del índice actual * volumen de tenencia) acumulado allAmount += positions[i].Amount; // Número de manos del contrato acumulado allProfit += positions[i].Profit; // Contrato flotante ganancias y pérdidas acumuladas allFrozen += positions[i].FrozenAmount; // Número total de manos contratadas congeladas ¿Qué quieres decir? ¿Qué quieres decir? if (allAmount === 0) { // Si el número de manos de contrato elegibles acumuladas después de haber completado el recorrido es 0, se devuelve null, es decir, no se mantiene ningún contrato limitado por condiciones No se puede hacer nada. ¿Qué quieres decir? return { // allAmount no es 0, devuelve la información de almacenamiento de un objeto después de la combinación. En la página web de Facebook de la empresa, se puede leer: FrozenAmount: todo congelado, Precio: _ N (allCost / allAmount), el precio de la compra es el mismo que el precio de la compra. Amount: todoAmount, Profit: todo Profit, Tipo: dirección Tipo de contrato: tipo de contrato ¿Qué es esto? ¿Qué quieres decir?

Función de apertura de operaciones, parámetros: objeto del intercambio, código del contrato, dirección, número de operaciones var initPosition = GetPosition ((e, contractType, direction); // Llama a la función GetPosition en la parte superior para obtener la información de almacenamiento después de la combinación. var isFirst = true; // establece el marcador isFirst (indica que el siguientewhile es el primer ciclo verdadero) var initAmount = initPosition? initPosition.Amount : 0; // Si initPosition es null, entonces initAmount se asigna a 0, de lo contrario se asigna a initPosition.Amount var positionNow = initPosition; // declara que una variable positionNow indica la información que se tiene actualmente mientras (verdadero) { // mientras var needOpen = opAmount; // declara la variable temporal needOpen y le asigna un valor con el parámetro cantidad de transacciones requeridas if (isFirst) { // Si es la primera vez que se ejecuta, sólo se actualiza el isFirst. La actualización es falsa, por lo que el siguiente ciclo ejecutará el bloque else. Si el número es 1 = falso; ¿Por qué? positionNow = GetPosition ((e, contractType, direction); // actualiza positionNow, la información de almacenamiento actual. if (positionNow) { // Si hay información de posicionamiento, el número de posiciones que se necesitan abrir después de needOpen es igual a la cantidad de operaciones que requiere el parámetro menos la diferencia de esta información de posicionamiento obtenida con la anterior (es decir, cuántas nuevas manos se abrieron) En el caso de las aplicaciones que se utilizan para la configuración de la página web, el nombre de la página web debe ser el siguiente: ¿Qué es eso? ¿Qué es eso? var insDetail = _C ((e. SetContractType, contractType); // Establece el tipo de contrato. // Log (para el almacenamiento inicial, initAmount, para el almacenamiento actual, positionNow, para el almacenamiento necesario, needOpen); if (needOpen < insDetail.MinLimitOrderVolume) { // Si el siguiente número de posiciones a abrir es menor que el número mínimo de posiciones a abrir en la lista de límites del contrato break; // salta del ciclo ¿Por qué no? if (!CanTrade(opAmount)) { // módulo de control de viento Detecta, salta del ciclo sin negociar si devuelve false. ¿Qué es lo que está pasando? ¿Por qué no? var depth = _C ((e.GetDepth); // Obtiene información sobre la profundidad del mercado. var amount = Math.min ((insDetail.MaxLimitOrderVolume, needOpen); // Limite que el volumen de envío no pueda ser mayor que el volumen máximo de envío del precio límite del contrato e.SetDirection ((direction == PD_LONG? buy: sell); // En función de los parámetros de dirección, se puede establecer una dirección más baja. El número de orden es el siguiente: if (direction == PD_LONG) { // Llama a diferentes API para realizar transacciones ((abre más o despeje más) dependiendo de la dirección del parámetro direction orderId = e.Buy ((depth.Asks[0].Price + (insDetail.PriceTick * SlideTick), Math.min ((amount, depth.Asks[0].Amount), contractType, Ask, depth.Asks[0]); el nombre de la página donde se encuentra el pedido es el siguiente: // Para más detalles, vea la documentación de la API, el precio de los futuros de los productos CTP debe ser un número entero de veces el valor insDetail. // La cantidad de unidades reales de las llamadas de API no es mayor que la cantidad de unidad de disco ¿Por qué? orderId = e.Sell ((depth.Bids[0].Price - (insDetail.PriceTick * SlideTick), Math.min ((amount, depth.Bids[0].Amount), contractType, Bid, depth.Bids[0]); el nombre de las ofertas es el mismo que el nombre de las ofertas. ¿Por qué no? // CancelPendingOrders (cancelar las órdenes pendientes) while (true) { // Después de la orden Interval de tiempo, cancela las órdenes pendientes. ¿Qué es lo que está pasando? var orders = _C ((e.GetOrders); // Obtiene todas las órdenes sin completar if (orders.length === 0) { // Si orders es un conjunto de números vacíos, salta el while actual ¿Qué es lo que está pasando? ¿Por qué no? for (var j = 0; j < orders.length; j++) { // Recorre una matriz de órdenes sin completar e.CancelOrder ((orders[j].Id); // Cancelar el pedido según el ID de la información del pedido en el índice actual. si (j < (orders.length - 1)) { // recorre el intervalo de tiempo, por un lado. Frecuencia demasiado alta. Sleep (Interval); // Sleep para suspender el Interval en milisegundos ¿Por qué no? ¿Por qué no? ¿Por qué no? } // Si el ciclo principal se retira mientras var ret = { // declara un objeto para ser devuelto Precio: 0, // el precio medio de la transacción cantidad: 0, // cantidad de transacciones position: positionNow // Información recientemente obtenida sobre el almacenamiento de esta variedad ¿Qué es esto? if (!positionNow) { // Si no hay información de almacenamiento, devuelve directamente el ret de inicialización ¿Cómo se hace esto? ¿Por qué no? if (!initPosition) { // Si no hay ninguna información de almacenamiento de esta variedad cuando se inicia la ejecución de la función actual. ret.price = positionNow.Price; // el precio en la posición ahora es el precio medio de la posición en la que se completó la transacción. ret.amount = positionNow.Amount; // también } else { // Si al principio ya había información sobre el almacenamiento de la variedad. ret.amount = positionNow.Amount - initPosition.Amount; // el valor de diferencia es el número de nuevas posiciones abiertas ret.price = _N (((((positionNow.Price * positionNow.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount); // El costo del nuevo incremento de esta transacción se obtiene por el precio medio de esta transacción. ¿Por qué no? Retorno de ret; // Retorno de ret ¿Por qué no?

Función Cover ((e, contractType) { // Función de liquidación de variedad única, parámetros: objeto de intercambio, código de contrato var insDetail = _C ((e.SetContractType, contractType); // Establece el tipo de contrato mientras (verdadero) { // ciclo principal mientras var n = 0; // Cuenta de operaciones de estacionamiento var opAmount = 0; // Declaración Operación Variable var positions = _C ((e.GetPosition); // Llama a la API para obtener información de almacenamiento, distingue entre la función de almacenamiento anterior. Para más detalles, consulte la documentación de la API. para (var i = 0; i < positions.length; i++) { // Recorrer información de almacenamiento si (positions[i].ContractType!= contractType) { // Si la información de tenencia del índice actual es contratable no es igual al contrato a operar, es decir: contractType Continuar; // Salta hacia adelante ¿Por qué no? var amount = Math.min ((insDetail.MaxLimitOrderVolume, positions[i].Amount); // controla el volumen máximo de transacciones que no es mayor que el volumen de las facturas La profundidad var. si (positions[i].Type == PD_LONG の の positions[i].Type == PD_LONG_YD) { // maneja varios puestos depth = _C ((e.GetDepth); // Llama a la API para obtener los datos de la cuenta actual opAmount = Math.min ((amount, depth.Bids[0].Amount); // restricción La cantidad de operaciones no es mayor que la cantidad de una fila de disco if (!CanTrade ((opAmount)) { // Detección del módulo de control del viento ¿Qué es lo que está pasando? ¿Por qué no? e.SetDirection ((positions[i].Type == PD_LONG? closebuy_today tab : closebuy tab); // configuración Dirección de transacción, para más información, véase la documentación de la API

            e.Sell(depth.Bids[0].Price - (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
                                                                                           // 执行平仓 API ,详细参见 API文档。
            n++;                                                                           // 操作计数累加
        } else if (positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) {    // 处理 空仓 类似多仓处理
            depth = _C(e.GetDepth);
            opAmount = Math.min(amount, depth.Asks[0].Amount);
            if (!CanTrade(opAmount)) {
                return;
            }
            e.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
            e.Buy(depth.Asks[0].Price + (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
            n++;
        }
    }
    if (n === 0) {                                                                         // 如果n 等于 0 ,即初始为0 ,在遍历时没有累加,没有可平的仓位。
        break;                                                                             // 跳出主while循环
    }
    while (true) {                                                                         // 间隔一定时间后, 取消所有挂单。类似Open函数的  CancelPendingOrders
        Sleep(Interval);
        var orders = _C(e.GetOrders);
        if (orders.length === 0) {
            break;
        }
        for (var j = 0; j < orders.length; j++) {
            e.CancelOrder(orders[j].Id);
            if (j < (orders.length - 1)) {
                Sleep(Interval);
            }
        }
    }
}

}

var trans = { // para mostrar información detallada de la cuenta en la barra de estado, traducción al chino, diccionario En la página de Facebook de la empresa, se puede ver una imagen de la cuenta de un inversor que tiene una cuenta en Twitter. En la actualidad, hay más de 100 millones de personas que trabajan en el sector de la construcción. En la actualidad, la mayoría de los bancos de Estados Unidos tienen una base de datos de los bancos centrales de Estados Unidos. El código de la compañía de corredores de Bitcoin, Bitcoin, es el código de la empresa de corredores de Bitcoin. La diferencia de dinero se está disparando, y la cantidad de dinero en efectivo está aumentando. En la actualidad, la mayoría de los usuarios de Facebook están usando la aplicación de Facebook como una herramienta de búsqueda. La Comisión de Asuntos Exteriores de la Unión Europea (UE) ha informado de que el gobierno de la República Popular de China (Rusia) está tomando medidas para que los ciudadanos puedan acceder a la información. El número de personas que se encuentran en el mercado de trabajo es muy alto. En la actualidad, la cantidad total de garantías es de alrededor de la mitad de la cantidad total de garantías que se ofrecen en el mercado. El código de identificación de la moneda es el código de identificación de la moneda. En la actualidad, la mayoría de los inversores de Bitcoin están en el mercado de divisas, y la mayoría de los inversores de Bitcoin están en el mercado de divisas de divisas. En la actualidad, la mayoría de los usuarios de Twitter están usando el sistema de mensajería móvil para enviar mensajes de texto. En la actualidad, la mayoría de las empresas de la región están operando en el sector de la construcción y la construcción. En la actualidad, la mayoría de las empresas de comercio electrónico están operando en el extranjero, y la mayoría de las empresas de comercio electrónico están en el extranjero. En el video, el actor explica cómo el dinero congelado se ha convertido en dinero en efectivo. En el caso de la Comisión de Cambio Frío (FrozenCommission), el precio de los servicios congelados es de $1,4 millones. En la actualidad, la mayoría de los usuarios de Facebook están usando el nombre de Facebook para describir sus preferencias. En la actualidad, la mayoría de los bancos de Estados Unidos tienen un saldo de hipotecas disponibles en el mercado de divisas. En la actualidad, la mayoría de las empresas que ofrecen préstamos de hipoteca a través de fondos hipotecarios no están financiando préstamos de hipoteca. En la actualidad, hay más de 100 millones de dólares en préstamos de hipotecas en todo el mundo. Los ingresos de los intereses aumentan, y los ingresos de los intereses también aumentan. El interés de la base de datos es el mismo que el de la base de datos. En el caso de la hipoteca, la hipoteca es una hipoteca. En la actualidad, hay una gran cantidad de empresas que ofrecen servicios de seguros de vida en todo el mundo. En la actualidad, la mayoría de las empresas que operan en el sector de la construcción de pisos están en una situación similar a la de los bancos. La última vez que el banco de reservas pagó el pre-balance, el banco de reservas pagó el pre-balance, y el banco de reservas pagó el pre-balance. La última vez que le dieron un préstamo, el banco le pagó un dólar y el banco le pagó un dólar. En la actualidad, la mayoría de los usuarios de Facebook están usando el teléfono móvil como su teléfono móvil. En el caso de los préstamos prefinanciados, los préstamos prefinanciados son los préstamos que se han pagado antes de que el préstamo fuera pagado. En la actualidad, la mayoría de las personas que se encuentran en el mercado de la hipoteca están en la misma situación que los que se encuentran en el mercado de la hipoteca. En la actualidad, la mayoría de los usuarios de Twitter están usando el nombre de Google como un nombre de usuario. El último préstamo fue pagado por una de las compañías de seguros más grandes del mundo. En la actualidad, hay más de 100 millones de personas en todo el mundo que trabajan en el sector de la energía. El banco de reservas: el banco de reservas de los futuros de la liquidación básica, el banco de reservas de la liquidación básica, el banco de reservas de la liquidación básica. En el caso de los residentes de las zonas rurales, el número de personas que se encuentran en las zonas rurales es el número de personas que viven en las zonas rurales. Los productos específicos que se almacenan en el almacén ganan y pierden, mientras que los productos especiales que se almacenan en el almacén pierden. La Comisión de Productos Específicos (SpecProductCommission) está encargada de la elaboración de los procedimientos para los productos especiales. El mercado de productos especializados garantiza el margen de oro, pero el mercado de productos especiales garantiza el margen de oro, lo que significa que el mercado de productos especiales garantiza el margen de oro. En la actualidad, la mayoría de los productos congelados están en el mercado, y el precio de los productos congelados es muy bajo. En la actualidad, la mayoría de los productos están congelados en el margen de congelación, lo que significa que los productos están congelados en el margen de congelación. En el caso de los productos especiales de aluminio, el margen de garantía de aluminio es el mismo que el margen de garantía del aluminio. Los productos específicos que se almacenan en el almacén ganan y pierden, mientras que los productos especiales que se almacenan en el almacén ganan y pierden. Pago por posición de producto específico (SpecProductPositionProfitByAlg): Pago por posición de producto específico calculado por el algoritmo de pérdidas y ganancias por posicionamiento de productos. El día de la negociación de las piezas: el día de la negociación de piezas. El dinero que se extrae de la moneda es el dinero que se extrae de la moneda. Los jugadores pueden sacar dinero con cuota de retiro, pero los jugadores no pueden hacerlo. ¿Qué es esto?

function AccountToTable ((jsStr, title) { // Función para exportar la información de la cuenta a la tabla de barras de estado, parámetros: la cadena de estructura JSON a mostrar, el título if (typeof(title) === undefined) { // Si no se ha enviado el parámetro title, se inicializa como: Información de la cuenta En la página de inicio de la página, el nombre de la cuenta se puede ver en el apartado de inicio. ¿Qué quieres decir? var tbl = { // declara un objeto de tabla para la transmisión de la función LogStatus, que se muestra en la barra de estado tipo: table, // tipo Especificado como table title: title, // Parámetro title asigna un valor al campo title de tbl cols: [Área de columnas de columnas, columnas de descripción de columnas, columnas de umbrales], // Tabla Título de columna rows: [] // un campo de la matriz en la que se almacenan los datos por línea de la tabla, inicialmente como una matriz vacía. ¿Qué es esto? Try { // Detecta una excepción var fields = JSON.parse ((jsStr); // analizar las cadenas de jsStr for (var k in fields) { // se recorre las propiedades de los campos, k es el valor de la propiedad, no entiendo puede consultar el tutorial de JS. If (k == AccountID k == BrokerID) { // Si la propiedad que se está recorriendo actualmente es una de estas dos propiedades, salta. Continuar ¿Qué quieres decir? var desc = trans[k]; // Obtenga la descripción desc en chino según el nombre de la propiedad del diccionario trans var v = fields[k]; // Obtiene el valor del nombre de la propiedad actual if (typeof(v) === number) { // Si el valor de la propiedad es de tipo numérico, se mantiene un decimal de 5 bits. V = N (v, 5); ¿Qué quieres decir? tbl.rows.push (([k, typeof(desc) === undefined? : desc, v]); // Presiona la matriz unidimensional de la combinación actual de propiedades, descripciones de propiedades, valores de propiedades en la matriz de propiedades de filas del objeto de la tabla tbl. ¿Qué quieres decir? } catch (e) {} // Captura las anomalías, pero no las procesa return tbl; // devuelve el objeto tbl ¿Qué quieres decir?

var PositionManager = (function() { // declara que una variable PositionManager acepta el valor de retorno de una función anónima, que devuelve el valor de un objeto construido function PositionManager ((e) { // declara que una función PositionManager está dentro de una función anónima. if (typeof(e) === undefined) { // Si no se transmite el parámetro e, por defecto se asigna a e la variable global exchange objeto de intercambio e = cambio; ¿Por qué no? if (e.GetName()!== Futures_CTP) { // Detecta si el objeto de la bolsa principal e es una bolsa de futuros de productos, si no es una excepción de lanzamiento. // sólo soporta CTP ¿Por qué no? this.e = e; // añade una propiedad e a la función actual (de hecho, también es un objeto) y le asigna el parámetro e this.account = null; // añade una cuenta La variable se inicia con null ¿Por qué no? // Obtener el caché PositionManager.prototype.Account = function() { // Añadir métodos a la función Account declarada anteriormente para el PositionManager si (!this.account) { // Si la propiedad de la cuenta de PositionManager es null this.account = _C ((this.e.GetAccount); // Llama a la función GetAccount (es decir, API de objetos de intercambio) del objeto de intercambio this.e para obtener información sobre la cuenta. ¿Por qué no? return this.account; // Este método devuelve la información de la cuenta de PositionManager.account. ¿Qué es esto? PositionManager.prototype.GetAccount = function ((getTable) { // Método de adición Este método obtiene la información de la cuenta más reciente Este.account = _C ((this.e.getAccount); este.account es el nombre de una cuenta de usuario. if (typeof(getTable)!== undefined && getTable) { // Para devolver información detallada de la información de la cuenta más recientemente obtenida como un objeto, getTable debe ser verdadero return AccountToTable ((this.e.GetRawJSON))) // Función GetRawJSON para más información en la documentación de la API ¿Por qué no? return this.account; // devuelve la información de la cuenta después de la actualización. ¿Qué es esto?

PositionManager.prototype.GetPosition = function(contractType, direction, positions) { // 给 PositionManager 添加方法 用于在主策略中调用该模板的 函数
    return GetPosition(this.e, contractType, direction, positions);
};

PositionManager.prototype.OpenLong = function(contractType, shares) {                  // 添加 开多仓 方法
    if (!this.account) {
        this.account = _C(this.e.GetAccount);
    }
    return Open(this.e, contractType, PD_LONG, shares);
};

PositionManager.prototype.OpenShort = function(contractType, shares) {                 // 添加 开空仓 方法
    if (!this.account) {
        this.account = _C(this.e.GetAccount);
    }
    return Open(this.e, contractType, PD_SHORT, shares);
};

PositionManager.prototype.Cover = function(contractType) {                             // 添加 平仓 方法
    if (!this.account) {
        this.account = _C(this.e.GetAccount);
    }
    return Cover(this.e, contractType);
};
PositionManager.prototype.CoverAll = function() {                                      // 添加 所有仓位全平方法
    if (!this.account) {
        this.account = _C(this.e.GetAccount);
    }
    while (true) {
        var positions = _C(this.e.GetPosition)
        if (positions.length == 0) {
            break
        }
        for (var i = 0; i < positions.length; i++) {                                   // 首先平掉 对冲合约 对冲合约 举例 MA709&MA705
            // Cover Hedge Position First
            if (positions[i].ContractType.indexOf('&') != -1) {
                Cover(this.e, positions[i].ContractType)
                Sleep(1000)
            }
        }
        for (var i = 0; i < positions.length; i++) {
            if (positions[i].ContractType.indexOf('&') == -1) {
                Cover(this.e, positions[i].ContractType)
                Sleep(1000)
            }
        }
    }
};
PositionManager.prototype.Profit = function(contractType) {                            // 添加计算收益的方法
    var accountNow = _C(this.e.GetAccount);
    return _N(accountNow.Balance - this.account.Balance);
};

return PositionManager;                                                                // 匿名函数返回 在自身内声明的 PositionManager 函数(对象)。

})();

$.NewPositionManager = function(e) { // Exporta una función y construye un objeto de PositionManager ¿Qué es lo que está pasando? ¿Qué es esto?

// Por medio de:http://mt.sohu.com/20160429/n446860150.shtml$.IsTrading = function ((symbol) { // Determina si el contrato está en el trámite. var now = new Date ((); // Obtiene el objeto de tiempo actual var day = now.getDay ((); // Obtiene el tiempo actual en un día específico de la semana. var hour = now.getHours ((); // Obtiene la hora de las 24 horas var minute = now.getMinutes ((); // Obtener qué minuto de un minuto en un minuto

if (day === 0 || (day === 6 && (hour > 2 || hour == 2 && minute > 30))) {              // 第一个过滤, day == 0 星期天  或者  day == 6 星期六并且
    return false;                                                                      // 2点30以后 。 星期五 夜盘结束。  返回 false  即所有品种不在交易时间
}
symbol = symbol.replace('SPD ', '').replace('SP ', '');                                // 正则表达式 匹配其交易系统用“SPD”表示跨期套利交易,若指令买进“SPD CF1609&CF17...
                                                                                       // 过滤掉 跨期套利的 合约编码
var p, i, shortName = "";
for (i = 0; i < symbol.length; i++) {                                                  // 遍历合约代码字符串,取出 代码(排除数字的部分)赋值给shortName 并且转换为大写
    var ch = symbol.charCodeAt(i);
    if (ch >= 48 && ch <= 57) {
        break;
    }
    shortName += symbol[i].toUpperCase();
}

var period = [                                                                         // 通常交易时间  9:00 - 10:15,
    [9, 0, 10, 15],                                                                    //             10:30 - 11:30
    [10, 30, 11, 30],                                                                  //              13:30 - 15:00
    [13, 30, 15, 0]
];
if (shortName === "IH" || shortName === "IF" || shortName === "IC") {                  // 如果是这些 品种,交易时间 period 调整
    period = [
        [9, 30, 11, 30],
        [13, 0, 15, 0]
    ];
} else if (shortName === "TF" || shortName === "T") {                                  // 国债品种  时间调整
    period = [
        [9, 15, 11, 30],
        [13, 0, 15, 15]
    ];
}


if (day >= 1 && day <= 5) {                                                            // 如果是 周一 到周五, 不考虑夜盘。 判断当前时间是否符合 period 设定的时间表
    for (i = 0; i < period.length; i++) {
        p = period[i];
        if ((hour > p[0] || (hour == p[0] && minute >= p[1])) && (hour < p[2] || (hour == p[2] && minute < p[3]))) {
            return true;                                                               // 符合遍历出的  时间表 中的 时间段,  即该品种在交易时间内。
        }
    }
}

var nperiod = [                                                                        // 额外判断 夜盘品种  nperiod[n][0] 是夜盘时间相同的一类
                                                                                       // 品种汇总,nperiod[n][1] 就是该类品种的夜盘交易时间
    [
        ['AU', 'AG'],
        [21, 0, 02, 30]
    ],
    [
        ['CU', 'AL', 'ZN', 'PB', 'SN', 'NI'],
        [21, 0, 01, 0]
    ],
    [
        ['RU', 'RB', 'HC', 'BU'],
        [21, 0, 23, 0]
    ],
    [
        ['P', 'J', 'M', 'Y', 'A', 'B', 'JM', 'I'],
        [21, 0, 23, 30]
    ],
    [
        ['SR', 'CF', 'RM', 'MA', 'TA', 'ZC', 'FG', 'IO'],
        [21, 0, 23, 30]
    ],
];
for (i = 0; i < nperiod.length; i++) {                                                // 遍历所有夜盘品种 交易时间段,对比当前时间。
    for (var j = 0; j < nperiod[i][0].length; j++) {
        if (nperiod[i][0][j] === shortName) {
            p = nperiod[i][1];
            var condA = hour > p[0] || (hour == p[0] && minute >= p[1]);
            var condB = hour < p[2] || (hour == p[2] && minute < p[3]);
            // in one day
            if (p[2] >= p[0]) {
                if ((day >= 1 && day <= 5) && condA && condB) {
                    return true;
                }
            } else {
                if (((day >= 1 && day <= 5) && condA) || ((day >= 2 && day <= 6) && condB)) {
                    return true;
                }
            }
            return false;
        }
    }
}
return false;

};

$.NewTaskQueue = function ((onTaskFinish) { // Función de construcción de objetos de cola para realizar transacciones de varias variedades. Parámetros: Función de retorno al final de la tarea. var self = {} // declara un objeto vacío self.ERR_SUCCESS = 0 // Define el mensaje de retorno de éxito error en la configuración del contrato self.ERR_GET_RECORDS = 2 // Obtención de error en la línea K self.ERR_GET_ORDERS = 3 // Obtención de errores de orden no completado error en la obtención de la información de almacenamiento. El error de la transacción se ha producido. self.ERR_GET_DEPTH = 6 // Obtención de un error de campo de profundidad self.ERR_NOT_TRADING = 7 // No está en el momento de la negociación self.ERR_BUSY = 8 // bloqueado

self.onTaskFinish = typeof(onTaskFinish) === 'undefined' ? null : onTaskFinish  // 如果在 初始化队列对象时没有 传入需要回调的匿名函数,该属性赋值为null,否则赋值回调函数
self.retryInterval = 300                                                        // 重试间隔 毫秒数
self.tasks = []                                                                 // 这个是一个重要的属性,队列中储存任务的数组。
self.pushTask = function(e, symbol, action, amount, arg, onFinish) {            // 给空对象添加函数,该函数是压入 新任务 到任务数组中。参数分别为:
                                                                                // 交易所对象、合约代码、执行动作、数量、回调函数参数、回调函数
    var task = {                                                                // 构造一个任务对象
        e: e,                                                                   // 交易所对象
        action: action,                                                         // 执行的动作
        symbol: symbol,                                                         // 合约代码
        amount: amount,                                                         // 操作数量
        init: false,                                                            // 是否初始化
        finished: false,                                                        // 是否任务完成
        dealAmount: 0,                                                          // 已处理的 量
        preAmount: 0,                                                           // 上一次的 量
        preCost: 0,                                                             // 上一次的 花费
        retry: 0,                                                               // 重试次数
        maxRetry: 10,                                                           // 最大重试次数
        arg: typeof(onFinish) !== 'undefined' ? arg : undefined,                // 如果没有传入 回调函数,此项 设置为 undefined
        onFinish: typeof(onFinish) == 'undefined' ? arg : onFinish              // 如果没有传入回调函数,把 arg 复制给 onFinish(实际上是 arg没传入,中间隔过去了)
    }
    
    switch (task.action) {                                                      // 根据执行的动作初始化描述信息
        case "buy":
            task.desc = task.symbol + " 开多仓, 数量 " + task.amount
            break
        case "sell":
            task.desc = task.symbol + " 开空仓, 数量 " + task.amount
            break
        case "closebuy":
            task.desc = task.symbol + " 平多仓, 数量 " + task.amount
            break
        case "closesell":
            task.desc = task.symbol + " 平空仓, 数量 " + task.amount
            break
        default:
            task.desc = task.symbol + " " + task.action + ", 数量 " + task.amount
    }

    self.tasks.push(task)                                                       // 压入任务数组中
    Log("接收到任务", task.desc)                                                  // 输出日志 显示 接收到任务。
}

self.cancelAll = function(e) {                                                  // 添加函数,取消所有,参数: 交易所对象
    while (true) {                                                              // 遍历未完成的所有订单,逐个取消。
        var orders = e.GetOrders();
        if (!orders) {                                                          // 所有API 调用都不重试,如果API调用失败,立即返回。
            return self.ERR_GET_ORDERS;
        }
        if (orders.length == 0) {
            break;
        }
        for (var i = 0; i < orders.length; i++) {
            e.CancelOrder(orders[i].Id);
            Sleep(self.retryInterval);
        }
    }
    return self.ERR_SUCCESS                                                      // 返回 完成标记
}

self.pollTask = function(task) {                                                 // 执行数组中弹出的任务
    var insDetail = task.e.SetContractType(task.symbol);                         // 切换到当前 任务 task 对象保存的合约类型
    if (!insDetail) {                                                            // 切换失败 立即返回
        return self.ERR_SET_SYMBOL;
    }
    var ret = null;
    var isCover = task.action != "buy" && task.action != "sell";                 // 根据执行的动作,设置 是否是平仓的 标记
    do {                                                                         // do while 循环,先执行 do 以内
        if (!$.IsTrading(task.symbol)) {                                         // 判断是否在交易时间
            return self.ERR_NOT_TRADING;                                         // 不在交易时间立即返回
        }
        if (self.cancelAll(task.e) != self.ERR_SUCCESS) {                        // 调用全部取消函数 ,如果不等于 完成状态
            return self.ERR_TRADE;                                               // 返回交易失败
        }
        if (!CanTrade(task.amount)) {                                            // 风控模块检测。
            ret = null
            break
        }
        var positions = task.e.GetPosition();                                    // 获取持仓信息
        // Error
        if (!positions) {
            return self.ERR_GET_POS;                                             // 如果调用获取持仓 API 错误,立即返回
        }
        // search position
        var pos = null;
        for (var i = 0; i < positions.length; i++) {                             // 遍历持仓信息,查找持仓合并持仓,类似 上面的 GetPosition 函数
            if (positions[i].ContractType == task.symbol && (((positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) && (task.action == "buy" || task.action == "closebuy")) || ((positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) && (task.action == "sell" || task.action == "closesell")))) {
                if (!pos) {
                    pos = positions[i];
                    pos.Cost = positions[i].Price * positions[i].Amount;
                } else {
                    pos.Amount += positions[i].Amount;
                    pos.Profit += positions[i].Profit;
                    pos.Cost += positions[i].Price * positions[i].Amount;
                }
            }
        }
        // record pre position
        if (!task.init) {                                                        // 如果任务没有初始化,执行以下
            task.init = true;                                                    // 更新为已初始化
            if (pos) {                                                           // 如果查找到之前的持仓,把之前的持仓数量、 花费 复制给task 的相应变量保存
                task.preAmount = pos.Amount;
                task.preCost = pos.Cost;
            } else {                                                             // 如果执行这个任务 时没有 ,同样的方向  同样合约的持仓,把task相关变量赋值0
                task.preAmount = 0;
                task.preCost = 0;
                if (isCover) {                                                   // 如果是 平仓动作,输出日志 : 找不到仓位,跳出循环。
                    Log("找不到仓位", task.symbol, task.action);
                    ret = null;
                    break;
                }
            }
        }
        var remain = task.amount;                                                // 声明一个局部变量,用 任务的属性 amount(任务设定的交易量) 初始化
        if (isCover && !pos) {                                                   // 如果 第二次循环中 , 该任务动作是平仓,并且 没有持仓了,给pos 赋值
            pos = {Amount:0, Cost: 0, Price: 0}
        }
        if (pos) {                                                               // 如果 pos 不为null 
            task.dealAmount = pos.Amount - task.preAmount;                       // 已经处理的任务量 等于 每次获取的持仓信息持仓量 与最初开始循环的初始持仓信息持仓量的差值
            if (isCover) {                                                       // 如果是 平仓动作, dealAmount 是负值, 这里取反操作
                task.dealAmount = -task.dealAmount;
            }
            remain = parseInt(task.amount - task.dealAmount);                    // 任务的 交易量 减去 已经处理的交易量  得出 剩余需要处理的交易量
            if (remain <= 0 || task.retry >= task.maxRetry) {                    // 如果剩余需要的交易量小于等于0(此处分析应该是不会小于0,有兴趣的可以分析下。) 或者重试次数大于最大重试上限.
                ret = {                                                          // 更新ret 对象,  更新为已经成交的信息,和 当前仓位信息。
                    price: (pos.Cost - task.preCost) / (pos.Amount - task.preAmount),
                    amount: (pos.Amount - task.preAmount),
                    position: pos
                };
                if (isCover) {                                                   // 如果是 平仓动作
                    ret.amount = -ret.amount;                                    // 平仓时计算出的是负值  ,取反操作
                    if (pos.Amount == 0) {                                       // 如果持仓量为0了, 把ret 的持仓信息 赋值为 null
                        ret.position = null;
                    }
                }
                break;                                                           // remain <= 0 || task.retry >= task.maxRetry 符合这个条件,跳出while循环
            }
        } else if (task.retry >= task.maxRetry) {                                // 如果不是 平仓操作。pos 为null 没有持仓(平仓操作 pos 此处不会是null)
            ret = null;                                                          // 并且 该任务重试测试 大于最大重试次数。跳出循环。
            break;                                                               // 即此时  , 超过最大重试次数,并且 没有增加持仓(开仓 每次都失败了。),跳出循环
        }

        var depth = task.e.GetDepth();                                           // 获取 深度数据
        if (!depth) {
            return self.ERR_GET_DEPTH;                                           // 获取失败立即返回
        }
        var orderId = null;                                                      // 订单ID
        var slidePrice = insDetail.PriceTick * SlideTick;                        // 计算具体滑价值
        if (isCover) {                                                           // 如果是平仓操作
            for (var i = 0; i < positions.length; i++) {                         // 遍历本轮的  API 返回的持仓信息。
                if (positions[i].ContractType !== task.symbol) {                 // 不是当前任务 品种的  跳过。
                    continue;
                }
                if (parseInt(remain) < 1) {                                      // 需要处理的 交易的量 如果小于1,跳出 while
                    break
                }
                var amount = Math.min(insDetail.MaxLimitOrderVolume, positions[i].Amount, remain);  // 在合约规定的最大下单量、持仓量、需要处理的量中取最小值。 
                if (task.action == "closebuy" && (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD)) {   // 如果是平多仓, 持仓信息 为 今日多仓  或者 昨日多仓
                    task.e.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");                  // 设置方向
                    amount = Math.min(amount, depth.Bids[0].Amount)                                                     // 根据盘口量 和 下单量 再取一个最小值。
                    orderId = task.e.Sell(_N(depth.Bids[0].Price - slidePrice, 2), amount, task.symbol, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
                                                                                                                        // 执行具体的 API 操作,以下平空类似
                } else if (task.action == "closesell" && (positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD)) {
                    task.e.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
                    amount = Math.min(amount, depth.Asks[0].Amount)
                    orderId = task.e.Buy(_N(depth.Asks[0].Price + slidePrice, 2), amount, task.symbol, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
                }
                // assume order is success insert
                remain -= amount;                                                // 假设是成功执行, 需要处理的交易量 减去 此次交易的量。
            }
        } else {                                                                 // 开仓
            if (task.action == "buy") {
                task.e.SetDirection("buy");
                orderId = task.e.Buy(_N(depth.Asks[0].Price + slidePrice, 2), Math.min(remain, depth.Asks[0].Amount), task.symbol, 'Ask', depth.Asks[0]);
            } else {
                task.e.SetDirection("sell");
                orderId = task.e.Sell(_N(depth.Bids[0].Price - slidePrice, 2), Math.min(remain, depth.Bids[0].Amount), task.symbol, 'Bid', depth.Bids[0]);
            }
        }
        // symbol not in trading or other else happend
        if (!orderId) {                                                          // 没有返回具体的ID ,可能是 交易不在交易队列,或者其他错误。
            task.retry++;                                                        // 累计重试次数
            return self.ERR_TRADE;                                               // 返回错误信息。即使不成功, 重新 执行该任务的时候 会重新一次流程。除了task对象的数据 所有数据都会刷新
        }
    } while (true);                                                              // 循环判断 恒为真
    task.finished = true                                                         // 如果在 while 循环中没有直接 return  顺序执行到此,则任务完成                                                      

    if (self.onTaskFinish) {                                                     // 如果队列控制对象的 回调函数 设置 不为null(即 self.onTaskFinish 存在)
        self.onTaskFinish(task, ret)                                             // 执行回调函数。把 task 任务 对象  和 交易的结果  ret 对象 传入回调函数。 
    }

    if (task.onFinish) {                                                         // 处理 任务的回调函数
        task.onFinish(task, ret);
    }
    return self.ERR_SUCCESS;
}

self.poll = function() {                                                         // 迭代执行 弹出 tasks 中的任务 ,并调用 pollTask 执行任务。
    var processed = 0                                                            // 未执行完成的任务计数 ,每次初始0
    _.each(self.tasks, function(task) {                                          // 迭代  可以搜索 _.each 的用法
        if (!task.finished) {                                                    // 如果 任务不是完成状态,
            processed++                                                          // 未完成任务 计数 累计
            self.pollTask(task)                                                  // 执行弹出的任务
        }
    })
    if (processed == 0) {                                                        // 如果没有未完成的任务,即 所有任务队列内的任务完成 ,执行清空 队列对象中 tasks 数组.
        self.tasks = []
    }
}

self.size = function() {                                                         // 给队列对象添加 函数 size 获取 任务队列 中 任务个数
    return self.tasks.length
}

return self                                                                      // 返回构造好的队列对象

}

$.AccountToTable = Cuenta a la tabla;


Más.