Add an alarm clock to the trading strategy
Tags: trading, strategy, cryptocurrency, fmzquant
Published: 2024-06-19 06:29:59

Traders who design trading strategies often ask me how to design timing functions for strategies so that strategies can handle certain tasks at specified times. For example, some intraday strategies need to close positions before the first section end in a trading day. How to design such requirements in the trading strategy? A strategy may use a lot of time control. In this way, we can encapsulate the time control function to minimize the coupling between the time control code and the strategy, so that the time control module can be reused and is concise in use.

## Design an "alarm clock"
```
// triggerTime: 14:58:00
function CreateAlarmClock(triggerHour, triggerMinute) {
    var self = {} // constructed object
    // Set members and functions to the constructed object below
    
    self.isTrigger = false // Has it been triggered that day
    self.triggerHour = triggerHour // The planned trigger hour
    self.triggerMinute = triggerMinute // The planned trigger minute
    self.nowDay = new Date().getDay() // what day is the current time
    
    self.Check = function() { // Check function, check trigger, return true when triggered, return false if not triggered
        var t = new Date() // Get the current time object
        var hour = t.getHours() // Get the current decimal: 0~23
        var minute = t.getMinutes() // Get the current minute: 0~59
        var day = t.getDay() // Get the current number of days

        if (day != self.nowDay) { // Judge, if the current day is not equal to the day of the record, reset the trigger flag as not triggered and update the number of days for the record
            self.isTrigger = false
            self.nowDay = day
        }

        if (self.isTrigger == false && hour == self.triggerHour && minute >= self.triggerMinute) {
            // Determine whether the time is triggered, if it meets the conditions, set the flag isTrigger to true to indicate that it has been triggered
            self.isTrigger = true
            return true
        }

        return false // does not meet the trigger condition, that is, it is not triggered
    }

    return self // return the constructed object
}
```
We have designed and implemented a function to create an alarm clock object (can be understood as a constructor), and other languages can directly design an alarm clock class (for example, using Python, we will implement one in Python later).

Design the function to construct the "alarm clock" object, and only need one line of code to create an "alarm clock" object in use.
```
var t = CreateAlarmClock(14, 58)
```
For example, create an object t and trigger it at 14:58 every day.
You can create another object t1, which is triggered every day at 9:00.
```
var t1 = CreateAlarmClock(9, 0)
```
## Test strategy
We write a test strategy. The strategy uses the simplest moving average system. The strategy is just for testing and does not care about the profit.
The strategy plan is to open a position (long, short, no trade) based on the daily moving average golden cross and dead cross when the market opens at 9:00 every day, and close the position at 14:58 in the afternoon (close at 15:00).
```
function CreateAlarmClock(triggerHour, triggerMinute) {
    var self = {} // constructed object
    // Set members and functions to the constructed object below
    
    self.isTrigger = false // Has it been triggered that day
    self.triggerHour = triggerHour // The planned trigger hour
    self.triggerMinute = triggerMinute // The planned trigger minute
    self.nowDay = new Date().getDay() // what day is the current time
    
    self.Check = function() {// Check function, check trigger, return true when triggered, return false if not triggered
        var t = new Date() // Get the current time object
        var hour = t.getHours() // Get the current decimal: 0~23
        var minute = t.getMinutes() // Get the current minute: 0~59
        var day = t.getDay() // Get the current number of days

        if (day != self.nowDay) {// Judge, if the current day is not equal to the day of the record, reset the trigger flag as not triggered and update the number of days for the record
            self.isTrigger = false
            self.nowDay = day
        }

        if (self.isTrigger == false && hour == self.triggerHour && minute >= self.triggerMinute) {
            // Determine whether the time is triggered, if it meets the conditions, set the flag isTrigger to true to indicate that it has been triggered
            self.isTrigger = true
            return true
        }

        return false // does not meet the trigger condition, that is, it is not triggered
    }

    return self // return the constructed object
}

function main() {
    var q = $.NewTaskQueue()
    var p = $.NewPositionManager()
    
    // You can write: var t = CreateAlarmClock(14, 58)
    // You can write: var t1 = CreateAlarmClock(9, 0)
    
    var symbol = "i2009"
    while (true) {
        if (exchange.IO("status")) {
            exchange.SetContractType(symbol)
            var r = exchange.GetRecords()
            if(!r || r.length <20) {
                Sleep(500)
                continue
            }
            if (/*Judging the conditions for opening a position at 9:00*/) {// You can write: t1.Check()
                var fast = TA.MA(r, 2)
                var slow = TA.MA(r, 5)
                
                var direction = ""
                if (_Cross(fast, slow) == 1) {
                    direction = "buy"
                } else if(_Cross(fast, slow) == -1) {
                    direction = "sell"
                }
                if(direction != "") {
                    q.pushTask(exchange, symbol, direction, 1, function(task, ret) {
                        Log(task.desc, ret)
                    })
                }
            }

            if (/*Judging 14:58 conditions for closing the position near the market close*/) {// You can write: t.Check()
                p.CoverAll()
            }

            q.poll()
            LogStatus(_D())
        } else {
            LogStatus(_D())
        }

        Sleep(500)
    }
}
```
Put the CreateAlarmClock function we have implemented in the strategy, and construct two "alarm clock" objects at the beginning of the main function. In the strategy to determine the position of opening and closing, add the code that the "alarm clock" object calls the Check function, such as the commented out part of the code.

## Backtest

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5z40u5d4vprkndklyzth.png)

You can see the backtest, opening positions after 9 am and closing positions at 14:58 pm.

It can also be used for multi-variety strategies. Multiple such "alarm clock" objects can be created in multi-variety strategies for time control of multiple varieties without affecting each other.

## Python language implements alarm clock class
Implementation and test code:
```
import time
class AlarmClock:
    def __init__(self, triggerHour, triggerMinute):
        self.isTrigger = False 
        self.triggerHour = triggerHour
        self.triggerMinute = triggerMinute
        self.nowDay = time.localtime(time.time()).tm_wday

    def Check(self):
        t = time.localtime(time.time())
        hour = t.tm_hour
        minute = t.tm_min
        day = t.tm_wday
        
        if day != self.nowDay:
            self.isTrigger = False
            self.nowDay = day
            
        if self.isTrigger == False and hour == self.triggerHour and minute >= self.triggerMinute:
            self.isTrigger = True
            return True
        
        return False 

def main():
    t1 = AlarmClock(14,58)
    t2 = AlarmClock(9, 0)
    while True:
        if exchange.IO("status"):
            LogStatus(_D(), "Already connected!")
            exchange.SetContractType("rb2010")
            ticker = exchange.GetTicker()
            if t1.Check():
                Log("Market Close", "#FF0000")
                
            if t2.Check():
                Log("Market Open", "#CD32CD")
        else :
            LogStatus(_D(), "not connected!")
        Sleep(500)
```
Backtest test run:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6nttirhund9s82xpv59d.png)

It should be noted that for backtest, the K-line cycle of the bottom layer cannot be set too large, otherwise the time detection point may be skipped directly and there will be no trigger.

From: https://www.fmz.com/digest-topic/5995