header source
my icon
esplo.net
ぷるぷるした直方体
Cover Image for Trading System Development and Investigation Memo (1)

Trading System Development and Investigation Memo (1)

about25mins to read

It is said that having an automated trading system (bot) that earns a little money every day can bring mental peace and health [citation needed].

I currently have a bot that earns a small but stable income, but there is still much room for improvement. It's clear that it will eventually hit a wall. Therefore, I have decided to strengthen the bot's theory and aim to create a bot that can operate in other environments and exchanges.

Although I have only been working on it for about two weeks and have only completed the core part, I think many improvements are necessary to generate profits. In this article, I will write about the improvements I have made and the research results, and I hope to convey the fun of creating a bot.

In short, this is just a memo for myself.

Premise

The exchange is Bitflyer, and the currency pair is FX_BTC_JPY. This exchange is suitable for bot trading because it has high liquidity and a large trading volume. On the other hand, it also has a violent side, with many bots already operating, and the system can become unstable, so it's not a straightforward task.

The spread is around 0.02% (if you believe the display). If you trade 1 unit of 500,000 yen, that's 100 yen, and if you trade 0.01 lots, you'll lose 1 yen (I'll measure the actual spread and slippage if necessary).

The method is simple: monitor the market, take a position when the conditions are met, and close it within about 1 minute (scalping). The trigger for taking a position is secret.

Goal

The short-term goal is to make a profit of almost the minimum lot size for 3 days. I'll put off setting a profit target of N yen per week for now and focus on reducing losses. While it's good to aim for a daily profit, the market environment has a significant impact, so I'll keep some leeway.

Current State of the Bot

The current bot has the following basic functions. However, since the verification period has just started, there is a high possibility of bugs.

  • Monitoring market conditions
  • Placing orders
  • Monitoring and closing positions
  • Monitoring exchange conditions (not trading if unstable)

By the way, this is the third-generation bot. The first generation is struggling elsewhere, and the second generation didn't work out. The first and second generations were made with Python, and this one is made with Rust.

Currently, I'm taking positions with IFD orders (market order, take profit at +900, and stop loss at -600) and closing them after 30 seconds.

Current Profit Situation

I ran the bot for about 11 hours from 0:00, and the result was a downward-sloping graph.

Screenshot_20181202-110610.webp

The graph display alone doesn't provide enough detail, so I created a tool with Python to display the trading history, and it looks like this (API's /v1/me/getchildorders is used, which will be discussed later).

...
2018-12-02 00:27:14, 0:01:12s, prof: -3.9, start: SELL, diff: 195.0, amount: 0.02,0.02
2018-12-02 01:31:36, 0:00:09s, prof: 15.48, start: BUY, diff: 774.0, amount: 0.02,0.02
2018-12-02 01:32:15, 0:00:17s, prof: 1.56, start: BUY, diff: 78.0, amount: 0.02,0.02
2018-12-02 01:33:04, 0:00:30s, prof: -18.26, start: SELL, diff: 913.0, amount: 0.02,0.02
2018-12-02 01:35:34, 0:00:18s, prof: -13.56, start: BUY, diff: -678.0, amount: 0.02,0.02
2018-12-02 01:36:04, 0:01:22s, prof: 9.8, start: SELL, diff: -490.0, amount: 0.02,0.02
2018-12-02 01:39:27, 0:00:02s, prof: 3.42, start: BUY, diff: 171.0, amount: 0.02,0.02
profit: -165.18000000000006, 120 trade

If necessary, I can output it in JSON or CSV format.

Hypothesis 1: Reversing the Trade Would Be Profitable

This is a hypothesis that anyone would think of. If the time is fixed, it's either going up or down, so reversing the trade would be a huge profit, right?

Looking at the history, there were 120 trades. If the spread is 0.02% (about 100 yen), and the lot is 0.02, that's 2 * 120 = 240 yen paid. In reality, it's -165 yen, so if there were no spread, it would be +75 yen. However, if I reversed the trade, it would be -315 yen, and the loss would expand.

However, this assumes that the spread is 0.02% and that there are no individual trade characteristics. It's possible that reversing the trade would be good under certain conditions, so this idea has some value.

In reality, I tried reversing the trade for a few hours, and the result was a downward-sloping graph, so I think I'm not mistaken.

Conclusion 1: The current trading direction is overall correct, so I'll keep it as it is for now.

Hypothesis 2: Abnormal Positions Are Causing Losses

Looking at the history, there are trades like this:

2018-12-01 21:17:04, 0:00:01s, prof: -4.5600000000000005, start: SELL, diff: 228.0, amount: 0.02,0.02
2018-12-01 21:17:05, 0:00:01s, prof: -1.06, start: SELL, diff: 53.0, amount: 0.02,0.02

Currently, the setting is to close the position 30 seconds after the trade. If it closes immediately, it would only pay the spread, which would contribute to the loss.

If this is a problem on the exchange side, it's possible that the spread suddenly expands, triggering the stop loss, or that the exchange is simply closing the position. However, I want to believe that such a thing wouldn't happen in a financial system.

If it's a bug on the bot side, it's possible that the bot is issuing abnormal orders, closing the position at an unusual time, or that the local state is messed up during the order. There are many possible issues, but I'll focus on the following two:

  • Hypothesis 2-1: The bot is issuing abnormal orders, causing the position to close immediately.
  • Hypothesis 2-2: The position is closing immediately due to a time lag, causing the price to deviate.

Motivating Example

To investigate the cause, I looked at the logs around the time of the last order. Luckily, the last order was abnormal, so I'll focus on that.

2018-12-02 01:39:27, 0:00:02s, prof: 3.42, start: BUY, diff: 171.0, amount: 0.02,0.02, open:482126.0-close:482297.0

The parameters of this order were as follows. I couldn't find any new orders after this.

{"minute_to_expire":10000,"order_method":"IFDOCO","parameters":[{"condition_type":"MARKET","product_code":"FX_BTC_JPY","side":"BUY","size":"0.02"},{"condition_type":"LIMIT","price":477918.0,"product_code":"FX_BTC_JPY","side":"SELL","size":"0.02"},{"condition_type":"STOP","product_code":"FX_BTC_JPY","side":"SELL","size":"0.02","trigger_price":476234.0}],"time_in_force":"GTC"}

Looking at this, the TP is 477918.0, and the SL is 476234.0. Now, let's look at the actual execution price...

open:482126.0, close:482297.0

It's completely different The possible causes are:

  • The local price data is different
    • The price data is delayed
    • There is a large lag in the price data
  • The local price data is correct
    • There is a large price movement during the order
    • The spread expands abnormally during the order
  • The exchange is executing at an abnormal price
    • The board is extremely thin
    • The spread expands abnormally during the order

I'll investigate these possibilities.

Investigation Log

I added logs and ran the bot, observing the logs around the suspicious order at 2018-12-02 14:32:20. It looks like it closed in 4 seconds.

2018-12-02 14:32:20, 0:00:04s, prof: 5.8, start: BUY, diff: 580.0, amount: 0.01,0.01, open:466470.0-close:467050.0

The price just before the order was as follows. 2018-12-02 14:32:20.393550181Z

before order price: {"bid":466056.0,"ask":466150.0}
bid: 2018-12-02T14:32:19.071246200Z
ask: 2018-12-02T14:32:19.118118700Z

The parameters of the new order (2018-12-02 14:32:20.405687224 UTC) are as follows.

{"minute_to_expire":10000,"order_method":"IFDOCO","parameters":[{"condition_type":"MARKET","product_code":"FX_BTC_JPY","side":"BUY","size":"0.01"},{"condition_type":"LIMIT","price":467050.0,"product_code":"FX_BTC_JPY","side":"SELL","size":"0.01"},{"condition_type":"STOP","product_code":"FX_BTC_JPY","side":"SELL","size":"0.01","trigger_price":465456.0}],"time_in_force":"GTC"}

The order details are as follows.

{
    "id": 735990320,
    "child_order_id": "JFX20181202-143224-489678F",
    "product_code": "FX_BTC_JPY",
    "side": "BUY",
    "child_order_type": "MARKET",
    "price": 0,
    "average_price": 466470,
    "size": 0.01,
    "child_order_state": "COMPLETED",
    "expire_date": "2018-12-09T13:12:20",
    "child_order_date": "2018-12-02T14:32:20",
    "child_order_acceptance_id": "JRF20181202-143220-015334",
    "outstanding_size": 0,
    "cancel_size": 0,
    "executed_size": 0.01,
    "total_commission": 0
}

The execution details are as follows.

{
    "id": 615318665,
    "side": "BUY",
    "price": 466470,
    "size": 0.01,
    "exec_date": "2018-12-02T14:32:24.32",
    "child_order_id": "JFX20181202-143224-489678F",
    "commission": 0,
    "child_order_acceptance_id": "JRF20181202-143220-015334"
}

The close order details are as follows.

{
    "id": 735991752,
    "child_order_id": "JFX20181202-143229-498110F",
    "product_code": "FX_BTC_JPY",
    "side": "SELL",
    "child_order_type": "LIMIT",
    "price": 467050,
    "average_price": 467050,
    "size": 0.01,
    "child_order_state": "COMPLETED",
    "expire_date": "2018-12-09T13:12:20",
    "child_order_date": "2018-12-02T14:32:24",
    "child_order_acceptance_id": "JRF20181202-143220-015343",
    "outstanding_size": 0,
    "cancel_size": 0,
    "executed_size": 0.01,
    "total_commission": 0
}

The close execution details are as follows.

{
    "id": 615320061,
    "side": "SELL",
    "price": 467050,
    "size": 0.01,
    "exec_date": "2018-12-02T14:32:45.743",
    "child_order_id": "JFX20181202-143229-498110F",
    "commission": 0,
    "child_order_acceptance_id": "JRF20181202-143220-015343"
}

Cause Investigation

I'm using WebSockets, but the price data is delayed by about 1,200ms. It's possible that there were no trades recently, but it's likely that there is a delay. I'll add more verification.

The bid/ask prices are 466,056/466,150, and the execution price is 466,470, which is about 300 yen away. It's possible that the delay is causing the deviation.

The order was placed and accepted within 600ms, and it took 4 seconds to execute. It's possible that the delay is causing the deviation.

……It's not 4 seconds!

Conclusion 2-1

Hypothesis 2-1: The bot is issuing abnormal orders, causing the position to close immediately.

The tool I created with Python was showing the time difference between child_order_date and child_order_date. If the order is completed with If-Done-OCO, the close order's child_order_date becomes the execution time of the parent order, so it looked like it closed in 4 seconds!

I'll fix the tool to display the correct logs (using /v1/me/getexecutions) and get the correct logs. Ah, what a relief!

Conclusion 2-1: The tool was wrong, and it looked like it closed in 4 seconds.

Conclusion 2-2

Hypothesis 2-2: The position is closing immediately due to a time lag, causing the price to deviate.

While the issue was resolved in 2-1, the Motivating Example doesn't fit. Here, I think the possible cause is that the execution price deviates due to a time lag, triggering the TP/SL immediately.

There are some suspicious points in the investigation process.

  • Is the information from WS delayed?
  • Is the execution time from the market order to the execution abnormally long (it took 4 seconds this time)?
    • There's a rumor that API orders are slow, but that's a mystery...

The time lag is suspicious, but I need detailed price data to determine if it's the cause. I'll prepare it for the next article.

Conclusion 2-2: There is a time lag of a few seconds. However, I need detailed price data to determine if it's the cause. I'll investigate it in the next article.

Summary of This Article

Like any product, it's common to be busy with bug fixes right after release and not be able to implement fundamental improvements. That's exactly what's happening this time.

Next time, I'll investigate the surrounding issues, collect data, and aim to reduce losses.

Share