Wednesday, June 28, 2023

Synthetic complex time series data: Python generator

The following Python code generates the synthetic time series based on real numbers and complex numbers.

This is useful to simulate the business cycles, the investment returns, and the other wave formed time series models of finance and macroeconomics.

You will need to adjust some parameters depending on your usage. 

Running this Python programme saves a csv file to Download folder in your PC but you may change owing to your preference.

# importing necessary tools
import os

import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
import pandas as pd
import random
import statistics
import scipy.linalg
from numpy import linalg as LA
from scipy.stats import qmc
from scipy.optimize import newton
from scipy import stats
import statsmodels.formula.api as sm

import math
import cmath

from scipy.linalg import hankel

# Showing the plots bigger
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (20,10)

# Initializing real numbers
x = -1.0
y = 0.001
 
# converting x and y into complex number
z = complex(x,y);

# defining complex number
i=complex(0,1)

# printing phase of a complex number using phase()
print ("The phase of complex number is : ",end="")
print (cmath.phase(z))

# signal Business Cycle
phi = [0.1, 0.3*i, 1*i, -1+3*i, -1-2*i, 0.03+0.5*i, 11*i, -9*i, 30*i]
alpha = [4, 3, 2, 2, 2, 1, 1, 1, 0.1]

# Defining the function generating the complex time series
def syn_exp(amp,freq,x):
    t=len(amp)
    y=[]
    for omg in range(len(x)):
        yi=0
        for ap in range(len(amp)):
            yi+=amp[ap]*cmath.exp(freq[ap]*x[omg])
        y.append(yi)
    return y

# sampling rate
M = 100

# number of exponentials in the signal
n = 600

# Generating the time trend for the complex time series
_2n_1=(2*n-1)+1
omega = [2*math.pi/M*(_0__2n_1) for _0__2n_1 in range(_2n_1)]
omega

# Generating the synthetic time series data of the phytical part (without noise)
f_syn = syn_exp(alpha, phi, omega)

# Generating the noise of the time trend
noise=[np.random.normal(0) for k in range(len(f_syn))]
noise=noise/LA.norm(noise)

# eps: noise level, also try 10^(-0)
eps =  10^(-1);
#eps = 0

# Combining the physical parts and the noise parts of the time series
# f = f_syn added with random noise
f = f_syn + eps*noise;

# plot the real part of the signal
def plot_signal(amp,freq,x):
    Mrend = 2*math.pi;
    Mint = math.pi/2;
    t=np.linspace(0, Mrend, 10000)
    M=len(t)
    x= [2*math.pi/M*(_0__2n_1) for _0__2n_1 in range(len(t))]
    F=syn_exp(amp,freq,x)
    F_real=[F[k].real for k in range(len(x))]
    plt.plot(F_real)
    plt.title('Signal: real part')
    plt.xlabel("'pi/2'__'pi'__'3pi/2'__'2pi'")
    plt.ylabel('')
    plt.show

plot_signal(alpha,phi,omega)

# Generating the time stamp
# ref: https://stackoverflow.com/questions/4479800/python-generate-dates-series
import datetime
stY=2023
stM=6
stD=1
fLen=len(f)

edY=stY+math.floor(fLen/365)+math.floor((stM+(fLen%365)/30)/12)
edM=math.floor((stM+(fLen%365)/30)%12)
edD=math.floor((stD+fLen%365%30))

dt = datetime.datetime(stY, stM, stD)
end = datetime.datetime(edY, edM, edD, 0, 0, 0)
step = datetime.timedelta(days=1)

TimeLine0 = []

while dt < end:
    TimeLine0.append(dt.strftime('%Y-%m-%d %H:%M:%S'))
    dt += step

TimeLine=TimeLine0[:fLen].copy()
len(TimeLine)

SensorId=[1]*fLen
len(f)

# Combining the time stamp and the time series data in Panda Dataframe
dict = {'Timestamp': TimeLine, 'SensorId': SensorId, 'Value': f, }
df = pd.DataFrame(dict)
df.tail()

# Download this time series data to your PC

FileLocation_Folder="C:\\Users\\OWNER\\Downloads" ## Change here for your PC!!!
Direct = (r"","\\ComplexTimeSeries.csv")
os.makedirs(FileLocation_Folder, exist_ok=True)  
df.to_csv(FileLocation_Folder.join(Direct))