El mercado es el campo de batalla, el comprador y el vendedor están siempre en el juego, que también es el tema eterno del negocio comercial.
En el comercio de alta frecuencia, hay dos tipos principales de estrategias. La estrategia del lado del comprador y la estrategia del lado del vendedor. La estrategia del lado del vendedor es generalmente una estrategia de creación de mercado, y los dos lados de estas estrategias son oponentes. Por ejemplo, la estrategia del comprador de arbitraje de alta frecuencia de suavizar todos los fenómenos irrazonables en el mercado a la velocidad más rápida, tomar la iniciativa de atacar el precio rápidamente, o comer el precio equivocado de otros creadores de mercado.
También hay una forma de analizar los datos históricos o las reglas de orden del mercado, para enviar las órdenes pendientes a un precio irrazonable por adelantado, y para enviar las órdenes de retiro con el rápido cambio del precio del mercado. Tales estrategias son comunes en el mercado pasivo, una vez que las órdenes pendientes se ejecutan, y después de un cierto beneficio o después de alcanzar la condición de stop-loss, la posición se cerrará.
Penny Jump se traduce en inglés es el significado de aumento de micro-precio. El principio es realizar un seguimiento del precio de compra y el precio de venta del mercado. Luego, de acuerdo con el precio del mercado, más o menos el aumento de micro-precio del precio de seguimiento, es obvio que esta es una estrategia de negociación pasiva, pertenece a la estrategia de creación de mercado del lado del vendedor. Su modelo de negocio y lógica es llevar a cabo transacciones bilaterales en órdenes de límite listadas en bolsa para proporcionar liquidez.
La estrategia de creación de mercado requiere una cierta cantidad de inventario en la mano, y luego se negocia tanto en el lado del comprador como del vendedor. El principal ingreso de esta estrategia es el retorno de la comisión proporcionada por el intercambio, así como la diferencia de precio obtenida comprando bajo y vendiendo alto.
Sabemos que hay muchos inversores minoristas en el mercado de operaciones, y también hay muchos inversores grandes, como:
Si un gran inversor quiere comprar 500 lotes de petróleo crudo, no hay tantas órdenes al precio actual para vender, y el inversor no quiere comprarlos al precio más alto. Si insisten en enviar la orden de compra al precio actual, el costo de los puntos de deslizamiento será demasiado. por lo tanto, tiene que enviar una orden pendiente al precio deseado. Todos los participantes en el mercado verán una orden de compra hugh que muestra el precio determinado.
Debido a este enorme pedido, parece torpe en el mercado, a veces lo llamamos "órdenes de elefante".
Selling Price 400.3, Order volume 50; buying price 400.1, Order volume 10.
De repente este elefante engorroso salta al mercado, y el precio de la oferta fue enviado al precio de 400.1.
Selling Price 400.3, Order volume 50; Buying price 400.1, Order volume 510.
Todos los traders saben que si hay una gran cantidad de órdenes pendientes a cierto precio, entonces este precio formará un fuerte soporte ((o resistencia).
Selling Price 400.3, Order volume 50; Buying price 400.2, Order volume 1,
el precio 400.1 se convierte en el precio de compra 2 en la profundidad de la cartera de órdenes.
Incluso si el precio no sube, en la posición de
En primer lugar, observar las oportunidades de negociación con una probabilidad muy baja del mercado, y hacer las estrategias correspondientes de acuerdo con la lógica de negociación. Si la lógica es compleja, es necesario utilizar el conocimiento matemático existente, utilizar el modelo para describir la naturaleza del fenómeno irracional tanto como sea posible, y reducir al mínimo el sobreajuste. Además, debe ser verificado por un motor de backtest que puede cumplir con el
¿Cuál es el significado de soportar
El
Además, algunos lectores pueden encontrar que la estrategia Penny Jump requiere oportunidades de comercio de mercado, es decir, la necesidad del mercado tiene al menos dos brechas de precio
La situación de aparición de la brecha de precios de dos
A continuación, observamos la diferencia entre el anterior
Después de limpiar la lógica de negociación, podemos usar el código para lograrlo. Dado que la plataforma FMZ Quant utiliza ejemplos de estrategia de escritura en C ++, aquí usamos C ++ para escribir esta estrategia, que es conveniente para que todos aprendan, y la variedad es los futuros de productos básicos.fmz.com> Iniciar sesión > Tablero > Biblioteca de estrategias > Nueva estrategia > Haga clic en el menú desplegable en la esquina superior izquierda > Seleccione C ++ para comenzar a escribir la estrategia, preste atención a los comentarios en el código a continuación.
A continuación, veamos la clase HFT, que tiene cinco métodos. El primer método es el método de construcción; el segundo método es obtener el día actual de la semana para determinar si es una nueva línea K; el tercer método es principalmente cancelar todos los pedidos no cumplidos y obtener información detallada de la posición, porque antes de que se coloque la orden, primero debe determinar el estado de la posición actual; el cuarto método se utiliza principalmente para imprimir cierta información, para esta estrategia, este método no es el principal; el más importante es el quinto método, Este método es principalmente responsable del procesamiento de la lógica de negociación y la colocación de pedidos.
/ / Define the HFT class
Class HFT {
Public:
HFT() {
// Constructor
}
Int getTradingWeekDay() {
// Get the current day of the week to determine if it is a new K line
}
State getState() {
/ / Get order data
}
Void stop() {
// Print orders and positions
}
Bool Loop() {
// Strategy logic and placing orders
}
};
// main function
Void main() {
LogReset(); // clear the log
SetErrorFilter("ready|timeout"); // Filter error messages
Log("Init OK"); // Print the log
HFT hft; // Create HFT object
While (hft.Loop()); // enter loop
Log("Exit"); // Program exits, prints the log
}
Así que vamos a ver cómo se implementa cada uno de los métodos en esta clase HFT, y cómo funciona el método más básico de Loop. De arriba a abajo, implementaremos la implementación específica de cada método uno por uno, y encontrarás que la estrategia original de alta frecuencia es muy simple. Antes de hablar sobre la clase HFT, primero definimos varias variables globales para almacenar los resultados del cálculo del objeto hft. Son: almacenamiento de estado de orden, estado de posición, mantenimiento de posición larga, mantenimiento de posición corta, precio de compra, cantidad de compra, precio de venta, cantidad de venta. Por favor, vea el código a continuación:
/ / Define the global enumeration type State
Enum State {
STATE_NA, // store order status
STATE_IDLE, // store position status
STATE_HOLD_LONG, // store long position directions
STATE_HOLD_SHORT, // store short position direction
};
/ / Define global floating point type variable
Typedef struct {
Double bidPrice; // store the buying price
Double bidAmount; // store the buying amount
Double askPrice; // store the selling price
Double askAmount; // store the selling amount
} Book;
Con las variables globales anteriores, podemos almacenar los resultados calculados por el objeto hft por separado, lo que es conveniente para llamadas posteriores por el programa. A continuación, hablaremos sobre la implementación específica de cada método en la clase HFT. Primero, el primer método HFT es un constructor que llama al segundo método getTradingWeekDay e imprime el resultado en el registro. El segundo método getTradingWeekDay obtiene el día actual de la semana para determinar si es una nueva línea K. También es muy simple de implementar, obtener la marca de tiempo, calcular la hora y la semana y, finalmente, devolver el número de semanas; el tercer método getState es un poco largo, solo describiré la idea general, para una explicación específica, puede ver los comentarios en el siguiente bloque de codificación.
A continuación, vamos a obtener todos los pedidos primero, devolver el resultado es una matriz normal, a continuación, atravesar esta matriz, uno por uno para cancelar el orden, a continuación, obtener los datos de posición, devolver una matriz, y luego atravesar esta matriz, obtener información de posición detallada, incluyendo: dirección, posición, ayer o posición actual, etc., y finalmente devolver el resultado; el cuarto método de parada es imprimir información; el código es el siguiente:
Public:
// Constructor
HFT() {
_tradingDay = getTradingWeekDay();
Log("current trading weekday", _tradingDay);
}
// Get the current day of the week to determine if it is a new K line
Int getTradingWeekDay() {
Int seconds = Unix() + 28800; // get the timestamp
Int hour = (seconds/3600)%24; // hour
Int weekDay = (seconds/(60*60*24))%7+4; // week
If (hour > 20) {
weekDay += 1;
}
Return weekDay;
}
/ / Get order data
State getState() {
Auto orders = exchange.GetOrders(); // Get all orders
If (!orders.Valid || orders.size() == 2) { // If there is no order or the length of the order data is equal to 2
Return STATE_NA;
}
Bool foundCover = false; // Temporary variable used to control the cancellation of all unexecuted orders
// Traverse the order array and cancel all unexecuted orders
For (auto &order : orders) {
If (order.Id == _coverId) {
If ((order.Type == ORDER_TYPE_BUY && order.Price < _book.bidPrice - _toleratePrice) ||
(order.Type == ORDER_TYPE_SELL && order.Price > _book.askPrice + _toleratePrice)) {
exchange.CancelOrder(order.Id, "Cancel Cover Order"); // Cancel order based on order ID
_countCancel++;
_countRetry++;
} else {
foundCover = true;
}
} else {
exchange.CancelOrder(order.Id); // Cancel order based on order ID
_countCancel++;
}
}
If (foundCover) {
Return STATE_NA;
}
// Get position data
Auto positions = exchange.GetPosition(); // Get position data
If (!positions.Valid) { // if the position data is empty
Return STATE_NA;
}
// Traverse the position array to get specific position information
For (auto &pos : positions) {
If (pos.ContractType == Symbol) {
_holdPrice = pos.Price;
_holdAmount = pos.Amount;
_holdType = pos.Type;
Return pos.Type == PD_LONG || pos.Type == PD_LONG_YD ? STATE_HOLD_LONG : STATE_HOLD_SHORT;
}
}
Return STATE_IDLE;
}
// Print orders and positions information
Void stop() {
Log(exchange.GetOrders()); // print order
Log(exchange.GetPosition()); // Print position
Log("Stop");
}
Finalmente, nos centramos en cómo la función Loop controla la lógica de estrategia y el orden. Si desea ver más cuidadosamente, puede consultar los comentarios en el código. Primero determine si la transacción CTP y el servidor del mercado están conectados; luego obtenga el saldo disponible de la cuenta y obtenga el número de semanas; luego establezca el código de variedad a negociar, llamando a la función oficial de SetContractType de FMZ Quant, y puede usar esta función para devolver los detalles de la variedad de negociación; luego llame a la función GetDepth para obtener los datos de profundidad del mercado actual. Los datos de profundidad incluyen: precio de compra, volumen de compra, precio de venta, volumen de venta, etc., y los almacenamos con variables, porque serán utilizados más adelante; Luego saque estos datos a la barra de estado para facilitar al usuario ver el estado actual del mercado; el código es el siguiente:
// Strategy logic and placing order
Bool Loop() {
If (exchange.IO("status") == 0) { // If the CTP and the quote server are connected
LogStatus(_D(), "Server not connect ...."); // Print information to the status bar
Sleep(1000); // Sleep 1 second
Return true;
}
If (_initBalance == 0) {
_initBalance = _C(exchange.GetAccount).Balance; // Get account balance
}
Auto day = getTradingWeekDay(); // Get the number of weeks
If (day != _tradingDay) {
_tradingDay = day;
_countCancel = 0;
}
// Set the futures contract type and get the contract specific information
If (_ct.is_null()) {
Log(_D(), "subscribe", Symbol); // Print the log
_ct = exchange.SetContractType(Symbol); // Set futures contract type
If (!_ct.is_null()) {
Auto obj = _ct["Commodity"]["CommodityTickSize"];
Int volumeMultiple = 1;
If (obj.is_null()) { // CTP
Obj = _ct["PriceTick"];
volumeMultiple = _ct["VolumeMultiple"];
_exchangeId = _ct["ExchangeID"];
} else { // Esunny
volumeMultiple = _ct["Commodity"]["ContractSize"];
_exchangeId = _ct["Commodity"]["ExchangeNo"];
}
If (obj.is_null() || obj <= 0) {
Panic("PriceTick not found");
}
If (_priceTick < 1) {
exchange.SetPrecision(1, 0); // Set the decimal precision of the price and the quantity of the order.
}
_priceTick = double(obj);
_toleratePrice = _priceTick * TolerateTick;
_ins = _ct["InstrumentID"];
Log(_ins, _exchangeId, "PriceTick:", _priceTick, "VolumeMultiple:", volumeMultiple); // print the log
}
Sleep(1000); // Sleep 1 second
Return true;
}
// Check orders and positions to set status
Auto depth = exchange.GetDepth(); // Get depth data
If (!depth.Valid) { // if no depth data is obtained
LogStatus(_D(), "Market not ready"); // Print status information
Sleep(1000); // Sleep 1 second
Return true;
}
_countTick++;
_preBook = _book;
_book.bidPrice = depth.Bids[0].Price; // "Buying 1" price
_book.bidAmount = depth.Bids[0].Amount; // "Buying 1" amount
_book.askPrice = depth.Asks[0].Price; // "Selling 1" price
_book.askAmount = depth.Asks[0].Amount; // "Selling 1" amount
// Determine the state of the port data assignment
If (_preBook.bidAmount == 0) {
Return true;
}
Auto st = getState(); // get the order data
// Print the port data to the status bar
LogStatus(_D(), _ins, "State:", st,
"Ask:", depth.Asks[0].Price, depth.Asks[0].Amount,
"Bid:", depth.Bids[0].Price, depth.Bids[0].Amount,
"Cancel:", _countCancel,
"Tick:", _countTick);
}
Después de haber hecho tanto, finalmente podemos colocar órdenes. Antes de la negociación, primero juzgamos el estado actual de la posición de retención del programa (sin posición de retención, órdenes de posición larga, órdenes de posición corta), aquí usamos el control de lógica si... si... si. Son muy simples, Si no hay posición de retención, la posición se abrirá de acuerdo con la condición lógica. Si hay posición de retención, la posición se cerrará de acuerdo con la condición lógica. Para facilitar la comprensión de todos, usamos tres párrafos para explicar la lógica, Para la parte de posición de apertura:
Primero declaramos una variable booleana, la usamos para controlar la posición de cierre; a continuación, necesitamos obtener la información de la cuenta corriente y registrar el valor de ganancia, luego determinar el estado de la orden de retiro, si el número de retiros excede el máximo establecido, imprimir la información relacionada en el registro; luego calcular el valor absoluto de la oferta actual y la diferencia de precio de oferta para determinar si hay más de 2 saltos entre el precio de oferta actual y el precio de compra.
A continuación, obtenemos el
Bool forceCover = _countRetry >= _retryMax; // Boolean value used to control the number of closings
If (st == STATE_IDLE) { // if there is no holding position
If (_holdAmount > 0) {
If (_countRetry > 0) {
_countLoss++; // failure count
} else {
_countWin++; // success count
}
Auto account = exchange.GetAccount(); // Get account information
If (account.Valid) { // If get account information
LogProfit(_N(account.Balance+account.FrozenBalance-_initBalance, 2), "Win:", _countWin, "Loss:", _countLoss); // Record profit value
}
}
_countRetry = 0;
_holdAmount = 0;
// Judging the status of withdrawal
If (_countCancel > _cancelMax) {
Log("Cancel Exceed", _countCancel); // Print the log
Return false;
}
Bool canDo = false; // temporary variable
If (abs(_book.bidPrice - _book.askPrice) > _priceTick * 1) { // If there is more than 2 hops between the current bid and ask price
canDo = true;
}
If (!canDo) {
Return true;
}
Auto bidPrice = depth.Bids[0].Price; // Buying 1 price
Auto askPrice = depth.Asks[0].Price; // Selling 1 price
Auto bidAmount = 1.0;
Auto askAmount = 1.0;
If (_preBook.bidPrice > _book.bidPrice && _book.askAmount < _book.bidAmount) { // If the previous buying price is greater than the current buying price and the current selling volume is less than the buying volume
bidPrice += _priceTick; // Set the opening long position price
bidAmount = 2; // set the opening long position volume
} else if (_preBook.askPrice < _book.askPrice && _book.bidAmount < _book.askAmount) { // If the previous selling price is less than the current selling price and the current buying volume is less than the selling volume
askPrice -= _priceTick; // set the opening short position volume
askAmount = 2; // set the opening short position volume
} else {
Return true;
}
Log(_book.bidPrice, _book.bidAmount, _book.askPrice, _book.askAmount); // Print current market data
exchange.SetDirection("buy"); // Set the order type to buying long
exchange.Buy(bidPrice, bidAmount); // buying long and open position
exchange.SetDirection("sell"); // Set the order type to selling short
exchange.Sell(askPrice, askAmount); // short sell and open position
}
A continuación, hablaremos sobre cómo cerrar una posición larga, primero establecer el tipo de orden de acuerdo con el estado actual de la posición, y luego obtener el precio de
Else if (st == STATE_HOLD_LONG) { // if holding long position
exchange.SetDirection((_holdType == PD_LONG && _exchangeId == "SHFE") ? "closebuy_today" : "closebuy"); // Set the order type, and close position
Auto sellPrice = depth.Asks[0].Price; // Get "Selling 1" price
If (sellPrice > _holdPrice) { // If the current "selling 1" price is greater than the long position opening price
Log(_holdPrice, "Hit #ff0000"); // Print long position opening price
sellPrice = _holdPrice + ProfitTick; // Set closing long position price
} else if (sellPrice < _holdPrice) { // If the current "selling 1" price is less than the long position opening price
forceCover = true;
}
If (forceCover) {
Log("StopLoss");
}
_coverId = exchange.Sell(forceCover ? depth.Bids[0].Price : sellPrice, _holdAmount); // close long position
If (!_coverId.Valid) {
Return false;
}
}
Finalmente, veamos cómo cerrar una posición corta. El principio es el opuesto a la posición larga de cierre mencionada anteriormente. Primero, según el estado de la posición actual, establezca el tipo de orden, y luego obtenga el precio de compra 1
Else if (st == STATE_HOLD_SHORT) { // if holding short position
exchange.SetDirection((_holdType == PD_SHORT && _exchangeId == "SHFE") ? "closesell_today" : "closesell"); // Set the order type, and close position
Auto buyPrice = depth.Bids[0].Price; // Get "buying 1" price
If (buyPrice < _holdPrice) { // If the current "buying 1" price is less than the opening short position price
Log(_holdPrice, "Hit #ff0000"); // Print the log
buyPrice = _holdPrice - ProfitTick; // Set the close short position price
} else if (buyPrice > _holdPrice) { // If the current "buying 1" price is greater than the opening short position price
forceCover = true;
}
If (forceCover) {
Log("StopLoss");
}
_coverId = exchange.Buy(forceCover ? depth.Asks[0].Price : buyPrice, _holdAmount); // close short position
If (!_coverId.Valid) {
Return false;
}
}
Lo anterior es un análisis completo de esta estrategia.https://www.fmz.com/strategy/163427) para copiar el código fuente de la estrategia completa sin configurar el entorno de backtest en FMZ Quant.
Para satisfacer la curiosidad de la negociación de alta frecuencia y ver los resultados con más claridad, esta estrategia de entorno de prueba de retroceso de la tarifa de transacción se establece en 0, lo que conduce a una lógica simple de velocidad rápida. si desea cubrir la tarifa de transacción para lograr rentabilidad en el mercado real. Se necesita más optimización.
FMZ Quant es un equipo basado exclusivamente en la tecnología que proporciona un mecanismo de backtest disponible y altamente eficiente para los entusiastas del comercio cuantitativo. Nuestro mecanismo de backtest simula un intercambio real, en lugar de una simple coincidencia de precios.