高频交易策略解析 - Penny Jump

Author: 发明者量化-小小梦, Created: 2023-11-03 17:36:56, Updated: 2023-11-03 22:19:32

img

高频交易是一项充满挑战和竞争的领域,它依赖于快速的交易执行和对市场微观结构的敏感洞察。其中一个备受瞩目的策略是Penny Jump,这个策略专注于利用市场中的"大象"来获取微小但频繁的利润。在这篇文章中,我们将详细解释Penny Jump策略的工作原理,同时深入探讨策略代码的细节,使初学者能够理解它是如何运作的。

理解Penny Jump策略

在股市中,"大象"通常是指那些机构投资人,他们希望买入或卖出大量股票,但又不愿意以市价交易。相反,他们选择在市场上挂出大量的限价单,即挂单,来表明他们的意图。这种行为在市场中引起了广泛的关注,因为大单交易可能会对市场产生重大影响。

例如,假设一只股票的市场深度原本是这样的:200 | $1.01 x $1.03 | 200。然后,一只"大象"进场,挂了一张3000股$1.01的买单。此时,市场深度将变为3,200 | $1.01 x $1.03 | 200。这一行为就像引入了一只"大象",它成为了市场中其他参与者的焦点。

  • 竞技市场 对于高频交易商来说,他们的利润主要来自市场微观结构的分析,以推测其他交易者的意图。一旦有大象出现,高频交易者将迅速建立仓位,以获取微小的价格波动。他们的目标是在短时间内频繁交易,积累微小但累积的利润。

  • 大象的困境 尽管大象可能希望在市场中大规模操作,但他们的行为也暴露了他们的交易意图,使他们成为高频交易者的目标。高频交易者会尝试提前建立仓位,然后在价格波动中获得利润。大象在市场中的存在可能会引发竞技市场的反应,从而对其交易策略造成影响。

  • 市场中的欺骗 现实中,大型机构投资人通常不会明目张胆地在市场中挂出大量买单或卖单,因为这样的行为可能会导致市场中的其他参与者采取对策,甚至操纵市场。因此,他们可能会采取策略来制造假象,吸引高频交易者进场,然后迅速出售或购买,以获取价格波动的利润。

Penny Jump策略的核心思想

Penny Jump策略的核心思想是,一旦市场中有大象出现并支撑了特定价格(例如$1.01),高频交易者将迅速将他们的出价提高一美分,例如到$1.02。这是因为高频交易者明白,大象的出现意味着这一价位有强大的买盘支撑,所以他们试图紧随其后,以期望价格上涨。当价格确实上涨到$1.03 x $1.05时,高频交易者可以迅速出售,赚取$0.01的利润。

不仅如此,高频交易者还可以在购买后,即使价格没有上涨,也能获得利润。因为他们知道大象支撑了底价,所以他们可以将股票迅速卖给这只大象,获得微小的差价利润。

解析Penny Jump策略代码

策略源码:https://www.fmz.com/strategy/358

上面提供的策略代码是一个示例,用于实现Penny Jump策略。以下是对代码的详细解释,使初学者能够理解它是如何工作的:

var Counter = {
    i: 0,
    w: 0,
    f: 0
};

// Variables
var InitAccount = null;

function CancelAll() {
    while (true) {
        var orders = _C(exchange.GetOrders);
        if (orders.length == 0) {
            break;
        }
        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id);
        }
        Sleep(Interval);
    }
}

function updateStatus(msg) {
    LogStatus("调戏次数:", Counter.i, "成功:", Counter.w, "失败:", Counter.f, "\n"+msg+"#0000ff\n"+new Date());
}

function main() {
    if (DisableLog) {
        EnableLog(false);
    }
    CancelAll();
    InitAccount = _C(exchange.GetAccount);
    Log(InitAccount);
    var i = 0;
    var locks = 0;
    while (true) {
        Sleep(Interval);
        var depth = _C(exchange.GetDepth);
        if (depth.Asks.length === 0 || depth.Bids.length === 0) {
            continue;
        }
        updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ",  卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
        var askPrice = 0;
        for (i = 0; i < depth.Asks.length; i++) {
            if (depth.Asks[i].Amount >= Lot) {
                askPrice = depth.Asks[i].Price;
                break;
            }
        }
        if (askPrice === 0) {
            continue;
        }
        var elephant = null;
        // skip Bids[0]
        for (i = 1; i < depth.Bids.length; i++) {
            if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
                break;
            }
            if (depth.Bids[i].Amount >= ElephantAmount) {
                elephant = depth.Bids[i];
                break;
            }
        }

        if (!elephant) {
            locks = 0;
            continue;
        }
        locks++;
        if (locks < LockCount) {
            continue;
        }
        locks = 0;

        updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
        exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
        var ts = new Date().getTime();
        while (true) {
            Sleep(CheckInterval);
            var orders = _C(exchange.GetOrders);
            if (orders.length == 0) {
                break;
            }
            if ((new Date().getTime() - ts) > WaitInterval) {
                for (var i = 0; i < orders.length; i++) {
                    exchange.CancelOrder(orders[i].Id);
                }
            }
        }
        var account = _C(exchange.GetAccount);
        var opAmount = _N(account.Stocks - InitAccount.Stocks);
        if (opAmount < 0.001) {
            Counter.f++;
            Counter.i++;
            continue;
        }
        updateStatus("买单得手: " + opAmount +", 开始出手...");
        exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
        var success = true;
        while (true) {
            var depth = _C(exchange.GetDepth);
            if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price-(STTick*PennyTick))) {
                success = false;
                updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
                CancelAll();
                account = _C(exchange.GetAccount);
                var opAmount = _N(account.Stocks - InitAccount.Stocks);
                if (opAmount < 0.001) {
                    break;
                }
                exchange.Sell(depth.Bids[0].Price, opAmount);
            }
            var orders = _C(exchange.GetOrders);
            if (orders.length === 0) {
                break;
            }
            Sleep(CheckInterval);
        }
        if (success) {
            Counter.w++;
        } else {
            Counter.f++;
        }
        Counter.i++;
        var account = _C(exchange.GetAccount);
        LogProfit(account.Balance - InitAccount.Balance, account);
    }
}

我将逐行解析您提供的策略代码,以帮助您更详细地理解它的运作方式。

var Counter = {
    i: 0,
    w: 0,
    f: 0
};

这段代码初始化一个名为Counter的对象,用于跟踪策略的交易统计信息。具体来说,它包括了三个属性:

  • i:表示总交易次数。
  • w:表示成功的交易次数。
  • f:表示失败的交易次数。

这些属性将在策略执行过程中记录和更新。

var InitAccount = null;

这一行代码初始化了一个名为InitAccount的变量,它将在策略开始执行时存储账户信息。

function CancelAll() {
    while (true) {
        var orders = _C(exchange.GetOrders);
        if (orders.length == 0) {
            break;
        }
        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id);
        }
        Sleep(Interval);
    }
}

这是一个名为CancelAll()的函数,其目的是取消市场上的所有未完成订单。让我们逐步解释其功能:

  • while (true):这是一个无限循环,它将一直执行,直到没有未完成的订单。
  • var orders = _C(exchange.GetOrders):这一行代码使用exchange.GetOrders函数获取当前账户所有挂出的订单,并将它们存储在orders变量中。
  • if (orders.length == 0):这一行代码检查是否存在未完成的订单。如果orders数组的长度为0,意味着没有未完成的订单,循环会被中断(break)。
  • for (var i = 0; i < orders.length; i++):这是一个for循环,它遍历所有未完成的订单。
  • exchange.CancelOrder(orders[i].Id):这一行代码使用exchange.CancelOrder()函数,通过订单的ID来取消每个订单。
  • Sleep(Interval):这一行代码引入了一个等待周期,等待一段时间(以毫秒为单位),以确保取消订单的操作不会过于频繁。

这个函数的目的是确保在执行主要策略之前,没有未完成的订单存在,以避免干扰主要策略的执行。

function updateStatus(msg) {
    LogStatus("调戏次数:", Counter.i, "成功:", Counter.w, "失败:", Counter.f, "\n" + msg + "#0000ff\n" + new Date());
}

这是一个名为updateStatus(msg)的函数,它用于更新交易状态信息并将其记录。它接受一个msg参数,通常包含有关当前市场状态的信息。函数的具体操作包括:

使用LogStatus()函数记录在策略运行时状态栏中显示的信息。它显示了有关交易次数、成功次数、失败次数的文本。 附加了msg参数,其中包含有关当前市场状态的信息。 附加了当前时间戳(new Date())以显示时间信息。 该函数的目的是记录和更新交易状态信息,以便在策略执行期间进行监视和分析。

function main() {
    if (DisableLog) {
        EnableLog(false);
    }
    CancelAll();
    InitAccount = _C(exchange.GetAccount);
    Log(InitAccount);
    var i = 0;
    var locks = 0;
    while (true) {
        Sleep(Interval);
        var depth = _C(exchange.GetDepth);
        if (depth.Asks.length === 0 || depth.Bids.length === 0) {
            continue;
        }
        updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ",  卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
        var askPrice = 0;
        for (i = 0; i < depth.Asks.length; i++) {
            if (depth.Asks[i].Amount >= Lot) {
                askPrice = depth.Asks[i].Price;
                break;
            }
        }
        if (askPrice === 0) {
            continue;
        }
        var elephant = null;
        // skip Bids[0]
        for (i = 1; i < depth.Bids.length; i++) {
            if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
                break;
            }
            if (depth.Bids[i].Amount >= ElephantAmount) {
                elephant = depth.Bids[i];
                break;
            }
        }

        if (!elephant) {
            locks = 0;
            continue;
        }
        locks++;
        if (locks < LockCount) {
            continue;
        }
        locks = 0;

        updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
        exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
        var ts = new Date().getTime();
        while (true) {
            Sleep(CheckInterval);
            var orders = _C(exchange.GetOrders);
            if (orders.length == 0) {
                break;
            }
            if ((new Date().getTime() - ts) > WaitInterval) {
                for (var i = 0; i < orders.length; i++) {
                    exchange.CancelOrder(orders[i].Id);
                }
            }
        }
        var account = _C(exchange.GetAccount);
        var opAmount = _N(account.Stocks - InitAccount.Stocks);
        if (opAmount < 0.001) {
            Counter.f++;
            Counter.i++;
            continue;
        }
        updateStatus("买单得手: " + opAmount +", 开始出手...");
        exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
        var success = true;
        while (true) {
            var depth = _C(exchange.GetDepth);
            if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price-(STTick*PennyTick))) {
                success = false;
                updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
                CancelAll();
                account = _C(exchange.GetAccount);
                var opAmount = _N(account.Stocks - InitAccount.Stocks);
                if (opAmount < 0.001) {
                    break;
                }
                exchange.Sell(depth.Bids[0].Price, opAmount);
            }
            var orders = _C(exchange.GetOrders);
            if (orders.length === 0) {
                break;
            }
            Sleep(CheckInterval);
        }
        if (success) {
            Counter.w++;
        } else {
            Counter.f++;
        }
        Counter.i++;
        var account = _C(exchange.GetAccount);
        LogProfit(account.Balance - InitAccount.Balance, account);
    }
}

这是策略的主要执行函数main(),它包含了策略的核心逻辑。让我们逐行解释其操作:

  • if (DisableLog):这一行代码检查DisableLog变量是否为true,如果是,将禁用日志记录。这是为了确保策略不会记录不必要的日志。

  • CancelAll():调用前面解释的CancelAll()函数,以确保没有未完成的订单存在。

  • InitAccount = _C(exchange.GetAccount):这一行代码获取当前账户的信息,并将其存储在InitAccount变量中。这将用于记录策略开始执行时的账户状态。

  • var i = 0;var locks = 0;:初始化两个变量i和locks,它们将在后续的策略逻辑中使用。

  • while (true):这是一个无限循环,主要用于策略的持续执行。

接下来,我们将逐行解释while (true)循环内的主要策略逻辑。

while (true) {
    Sleep(Interval);
    var depth = _C(exchange.GetDepth);
    if (depth.Asks.length === 0 || depth.Bids.length === 0) {
        continue;
    }
    updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ",  卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
  • Sleep(Interval):这一行代码让策略休眠一段时间,以控制策略的执行频率。Interval参数定义了休眠的时间间隔(以毫秒为单位)。

  • var depth = _C(exchange.GetDepth):获取当前市场深度信息,包括卖单和买单的价格和数量。这些信息将存储在depth变量中。

  • if (depth.Asks.length === 0 || depth.Bids.length === 0):这一行代码检查市场深度信息,确保卖单和买单都存在。如果其中之一不存在,表示市场可能没有足够的交易信息,那么策略会继续等待。

  • updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ", 卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks):这一行代码调用updateStatus函数,更新策略的状态信息。它记录了当前市场状态,包括买一价、卖一价以及之前锁定的次数(locks)。

    var askPrice = 0;
    for (i = 0; i < depth.Asks.length; i++) {
        if (depth.Asks[i].Amount >= Lot) {
            askPrice = depth.Asks[i].Price;
            break;
        }
    }
    if (askPrice === 0) {
        continue;
    }
    var elephant = null;

  • var askPrice = 0;:初始化askPrice变量,它将用于存储满足条件的卖单价格。

  • for (i = 0; i < depth.Asks.length; i++):这是一个for循环,用于遍历市场卖单的价格和数量信息。

  • if (depth.Asks[i].Amount >= Lot):在循环中,检查每个卖单的数量是否大于或等于指定的Lot(手数)。如果是,将该卖单的价格存储在askPrice中,并终止循环。

  • if (askPrice === 0):如果没有找到满足条件的卖单(askPrice仍为0),则策略会继续等待,跳过后续的操作。

  • var elephant = null;:初始化elephant变量,它将用于存储被认定为“大象”的买单信息。

    for (i = 1; i < depth.Bids.length; i++) {
        if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
            break;
        }
        if (depth.Bids[i].Amount >= ElephantAmount) {
            elephant = depth.Bids[i];
            break;
        }
    }

    if (!elephant) {
        locks = 0;
        continue;
    }
    locks++;
    if (locks < LockCount) {
        continue;
    }
    locks = 0;

继续遍历市场买单的价格和数量信息,跳过第一个买单(Bids[0])。

  • if ((askPrice - depth.Bids[i].Price) > ElephantSpace):检查当前买单价格与askPrice之间的差距是否大于ElephantSpace。如果是,表示已经足够远离“大象”,策略不再继续寻找。

  • if (depth.Bids[i].Amount >= ElephantAmount):检查当前买单的数量是否大于或等于ElephantAmount,如果是,将该买单信息存储在elephant变量中。

  • if (!elephant):如果没有找到“大象”,则将锁定次数locks重置为0,并继续等待。

locks++:如果找到了“大象”,将锁定次数递增。这是为了确保在一段时间内多次确认“大象”存在后再执行策略。

  • if (locks < LockCount):检查锁定次数是否达到要求(LockCount)。如果未达到要求,继续等待。
    updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
    exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
    var ts = new Date().getTime();
    while (true) {
        Sleep(CheckInterval);
        var orders = _C(exchange.GetOrders);
        if (orders.length == 0) {
            break;
        }
        if ((new Date().getTime() - ts) > WaitInterval) {
            for (var i = 0; i < orders.length; i++) {
                exchange.CancelOrder(orders[i].Id);
            }
        }
    }

  • updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant)):调用updateStatus函数,记录策略当前状态,包括找到的“大象”所在的档位和相关信息。这将在策略的状态栏中显示。

  • exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant):使用exchange.Buy函数购买找到的“大象”。购买价格为elephant.Price + PennyTick,购买数量为Lot,并将购买操作描述为"Bids[" + i + “]”。

  • var ts = new Date().getTime():获取当前时间的时间戳,以便后续计算时间间隔。

  • while (true):进入一个新的无限循环,用于等待“大象”购买订单的执行。

  • Sleep(CheckInterval):策略休眠一段时间,以控制检查订单状态的频率。

  • var orders = _C(exchange.GetOrders):获取当前账户的所有订单信息。

  • if (orders.length == 0):检查是否存在未完成的订单,如果没有,跳出循环。

  • (new Date().getTime() - ts) > WaitInterval:计算当前时间与购买“大象”时的时间间隔,如果超过WaitInterval,则表示等待超时。

  • for (var i = 0; i < orders.length; i++):遍历所有未完成的订单。

  • exchange.CancelOrder(orders[i].Id):使用exchange.CancelOrder函数取消每个未完成的订单。

    var account = _C(exchange.GetAccount);
    var opAmount = _N(account.Stocks - InitAccount.Stocks);
    if (opAmount < 0.001) {
        Counter.f++;
        Counter.i++;
        continue;
    }
    updateStatus("买单得手: " + opAmount + ", 开始出手...");
    exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
    var success = true;
    while (true) {
        var depth = _C(exchange.GetDepth);
        if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price - (STTick * PennyTick))) {
            success = false;
            updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
            CancelAll();
            account = _C(exchange.GetAccount);
            var opAmount = _N(account.Stocks - InitAccount.Stocks);
            if (opAmount < 0.001) {
                break;
            }
            exchange.Sell(depth.Bids[0].Price, opAmount);
        }
        var orders = _C(exchange.GetOrders);
        if (orders.length === 0) {
            break;
        }
        Sleep(CheckInterval);
    }
    if (success) {
        Counter.w++;
    } else {
        Counter.f++;
    }
    Counter.i++;
    var account = _C(exchange.GetAccount);
    LogProfit(account.Balance - InitAccount.Balance, account);
}

  • var account = _C(exchange.GetAccount):获取当前账户信息。

  • var opAmount = _N(account.Stocks - InitAccount.Stocks):计算购买“大象”后账户中的资产变化。如果变化小于0.001,表示购买失败,将失败次数增加,并继续下一次循环。

  • updateStatus("买单得手: " + opAmount + ", 开始出手..."):记录成功购买“大象”的信息,包括购买数量。

  • exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount):使用exchange.Sell函数出售成功购买的“大象”,以获取利润。出售价格为elephant.Price + (PennyTick * ProfitTick)。

进入一个新的无限循环,用于等待出售订单的执行。

  • var depth = _C(exchange.GetDepth):获取市场深度信息。

  • if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price - (STTick * PennyTick))):检查市场深度信息,如果市场价格已经下跌到止损价位,则执行止损操作。

  • CancelAll():调用CancelAll()函数,取消所有未完成的订单,以避免持仓风险。

  • if (opAmount < 0.001):再次检查购买数量,如果小于0.001,表示购买失败,跳出循环。

  • exchange.Sell(depth.Bids[0].Price, opAmount):执行止损操作,以当前市场最低价出售剩余的资产。

最后,根据交易成功与否,更新成功次数和失败次数,并记录交易利润。

这就是整个策略的逐行解释。这个策略的核心思想是在市场中寻找“大象”(大量买单),购买并出售以获取微小的利润。它包括了多个重要的参数,如购买数量(Lot)、出错重试间隔(Interval)、大象级别(ElephantAmount)、大象距离(ElephantSpace)等,以调整策略的行为。

总的来说,这个策略是一个高频交易策略,旨在利用市场深度信息,识别大量买单并在短时间内进行买卖交易。它需要不断地监测市场并执行买卖操作,以迅速获取微小的利润。然而,这也是一个高风险的策略,因为它需要快速反应市场波动,同时需要考虑风险管理和止损机制,以避免重大亏损。

请注意,这个策略是基于特定的市场和交易平台,对于不同的市场和交易所,可能需要进行适当的调整和优化。在实际应用中,投资者需要谨慎测试和评估策略的性能,以确保其符合投资目标和风险承受能力。

当您继续执行策略时,它会不断循环执行以下操作:

1、首先,策略会检查市场的深度信息,以了解当前的卖单和买单情况。

2、接下来,策略将尝试寻找符合条件的卖单,具体条件是卖单数量大于或等于Lot(手数)。如果找到符合条件的卖单,将记录卖单的价格为askPrice。

3、然后,策略会继续寻找“大象”(大量买单)。它会遍历市场上的买单,跳过第一个买单(通常是最高价位的买单)。如果找到符合条件的“大象”,将记录“大象”的信息,并增加锁定次数(locks)。

4、如果连续找到足够的“大象”次数(由LockCount参数控制),策略会进一步执行以下操作:

  • 调用updateStatus函数,记录“大象”所在的档位和相关信息。
  • 使用exchange.Buy函数购买“大象”,购买价格为elephant.Price + PennyTick,购买数量为Lot。
  • 开始一个新的无限循环,用于等待购买订单的执行。
  • 检查订单状态,如果订单已完成,跳出循环。
  • 如果等待时间超过了设定的等待间隔(WaitInterval),则取消所有未完成的订单。
  • 计算购买成功后账户资产的变化,如果变化小于0.001,表示购买失败,增加失败次数,并继续下一次循环。
  • 记录成功购买“大象”的信息,包括购买数量。

5、接下来,策略会继续进入一个新的无限循环,用于等待卖出操作的执行。在这个循环中,它会执行以下操作:

  • 获取市场深度信息,检查市场价格是否已经达到止损价位。
  • 如果市场价格已达到或低于止损价位,将执行止损操作,即出售剩余的资产。
  • 调用CancelAll函数,取消所有未完成的订单,以降低持仓风险。
  • 再次检查购买成功后账户资产的变化,如果变化小于0.001,表示购买失败,跳出循环。
  • 最后,记录交易成功与否,并根据交易结果更新成功次数和失败次数。

整个策略不断循环执行上述操作,以尽可能多地捕捉“大象”并获取微小的利润。这是一个高频交易策略,需要快速响应市场变化,同时需要考虑风险管理和止损机制以保护资本。投资者应慎重考虑使用此策略,尤其是在高度波动的市场中。

结语

Penny Jump策略是高频交易中的一个典型示例,它展示了市场参与者之间的微妙博弈和竞争。在加密货币市场,这种策略尤为突出,因为市场波动大,机构投资人和高频交易者都在追求快速的利润。然而,这也使市场变得充满挑战,需要不断适应和调整策略,以维持竞争优势。在这个激烈竞争的世界里,只有那些善于洞察市场的微结构并迅速作出反应的交易者才能获得成功。


More