When writing and using strategies, we often use some rarely used K-line period data. However, exchanges and data sources do not provide data on these periods. It can only be synthesized by using data with an existing period. The synthesized algorithm already has a JavaScript version (link). In fact, it is easy to transplant a piece of JavaScript code to Python. Next, let's write a Python version of the K-line synthesis algorithm.

### JavaScript version

```  function GetNewCycleRecords (sourceRecords, targetCycle) {    // K-line synthesis function
var ret = []

// Obtain the period of the source K-line data first
if (!sourceRecords || sourceRecords.length < 2) {
return null
}
var sourceLen = sourceRecords.length
var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time

if (targetCycle % sourceCycle != 0) {
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
throw "targetCycle is not an integral multiple of sourceCycle."
}

if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) {
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
throw "targetCycle cannot complete the cycle."
}

var multiple = targetCycle / sourceCycle

var isBegin = false
var count = 0
var high = 0
var low = 0
var open = 0
var close = 0
var time = 0
var vol = 0
for (var i = 0 ; i < sourceLen ; i++) {
// Get the time zone offset value
var d = new Date()
var n = d.getTimezoneOffset()

if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
isBegin = true
}

if (isBegin) {
if (count == 0) {
high = sourceRecords[i].High
low = sourceRecords[i].Low
open = sourceRecords[i].Open
close = sourceRecords[i].Close
time = sourceRecords[i].Time
vol = sourceRecords[i].Volume

count++
} else if (count < multiple) {
high = Math.max(high, sourceRecords[i].High)
low = Math.min(low, sourceRecords[i].Low)
close = sourceRecords[i].Close
vol += sourceRecords[i].Volume

count++
}

if (count == multiple || i == sourceLen - 1) {
ret.push({
High : high,
Low : low,
Open : open,
Close : close,
Time : time,
Volume : vol,
})
count = 0
}
}
}

return ret
}```

There are JavaScript algorithms. Python can be translated and transplanted line by line. If you encounter JavaScript built-in functions or inherent methods, you can go to Python to find the corresponding methods. Therefore, the migration is easy.
The algorithm logic is exactly the same, except that JavaScript function calls `var n=d.getTimezoneOffset()`. When migrating to Python,`n=time.altzone` in Python's time library is used instead. Other differences are only in terms of language grammar (such as the use of for loops, Boolean values, logical AND, logical NOT, logical OR, etc.).

Migrated Python code:

```import time

def GetNewCycleRecords(sourceRecords, targetCycle):
ret = []

# Obtain the period of the source K-line data first
if not sourceRecords or len(sourceRecords) < 2 :
return None

sourceLen = len(sourceRecords)
sourceCycle = sourceRecords[-1]["Time"] - sourceRecords[-2]["Time"]

if targetCycle % sourceCycle != 0 :
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
raise "targetCycle is not an integral multiple of sourceCycle."

if (1000 * 60 * 60) % targetCycle != 0 and (1000 * 60 * 60 * 24) % targetCycle != 0 :
Log("targetCycle:", targetCycle)
Log("sourceCycle:", sourceCycle)
Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
raise "targetCycle cannot complete the cycle."

multiple = targetCycle / sourceCycle

isBegin = False
count = 0
barHigh = 0
barLow = 0
barOpen = 0
barClose = 0
barTime = 0
barVol = 0

for i in range(sourceLen) :
# Get the time zone offset value
n = time.altzone

if ((1000 * 60 * 60 * 24) - (sourceRecords[i]["Time"] * 1000) % (1000 * 60 * 60 * 24) + (n * 1000)) % targetCycle == 0 :
isBegin = True

if isBegin :
if count == 0 :
barHigh = sourceRecords[i]["High"]
barLow = sourceRecords[i]["Low"]
barOpen = sourceRecords[i]["Open"]
barClose = sourceRecords[i]["Close"]
barTime = sourceRecords[i]["Time"]
barVol = sourceRecords[i]["Volume"]
count += 1
elif count < multiple :
barHigh = max(barHigh, sourceRecords[i]["High"])
barLow = min(barLow, sourceRecords[i]["Low"])
barClose = sourceRecords[i]["Close"]
barVol += sourceRecords[i]["Volume"]
count += 1

if count == multiple or i == sourceLen - 1 :
ret.append({
"High" : barHigh,
"Low" : barLow,
"Open" : barOpen,
"Close" : barClose,
"Time" : barTime,
"Volume" : barVol,
})
count = 0

return ret

# Test
def main():
while True:
r = exchange.GetRecords()
r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)

ext.PlotRecords(r2, "r2")
Sleep(1000)```

### Test

Huobi market chart

4-hour chart of backtest synthesis

The above code is for reference only. If it is used in specific strategies, please modify and test according to the specific requirements.