import random
suits = ['红桃', '黑桃', '梅花', '方块']
faces = ['2', '3', '4','5','6','7','8','9','10', 'J', 'Q', 'K', 'A']
flag = 'yes'
while flag == 'yes':
    mySuit = random.choice(suits)
    myFace = random.choice(faces)
    yourSuit = random.choice(suits)
    yourFace = random.choice(faces)
    print('我的牌是',mySuit+myFace,'，你的牌是',yourSuit+yourFace)
    if faces.index(myFace) > faces.index(yourFace):
        print('我赢了！')
    elif faces.index(myFace) < faces.index(yourFace):
        print('你赢了！')
    else:
        print('平局！')
    flag = input('继续游戏请输入yes，停止游戏请输入no：')


import pandas as pd

def date2years(d, default=None, default_min_date=1900, default_max_date=2018):
    if pd.notnull(d):
        first_jan_this_year = pd.datetime(year=d.year, month=1, day=1)
        day_of_this_year = d - first_jan_this_year
        first_jan_next_year = pd.datetime(year=d.year + 1, month=1, day=1)
        days_in_this_year = first_jan_next_year - first_jan_this_year
        date = d.year + day_of_this_year / days_in_this_year
        max_date, min_date = date, date
        if date == d.year:
            max_date = d.year + (days_in_this_year.days - 1) / days_in_this_year.days
            return None, date, max_date
        return date, min_date, max_date
    else:
        return default, default_min_date, default_max_date

if '__main__' == __name__:
    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument('--data', required=True, type=str)
    parser.add_argument('--dates', required=True, type=str)
    parser.add_argument('--date_col', required=True, type=str)
    params = parser.parse_args()

    df = pd.read_csv(params.data, index_col=0)[[params.date_col]]
    try:
        df[params.date_col] = pd.to_datetime(df[params.date_col], format='%d/%m/%Y')
    except ValueError:
        try:
            df[params.date_col] = pd.to_datetime(df[params.date_col], infer_datetime_format=True)
        except ValueError:
            try:
                df[params.date_col] = pd.to_datetime(df[params.date_col], format='%Y.0')
            except ValueError:
                raise ValueError('Could not infer the date format for column "{}", please check it.'
                                 .format(params.date_col))

    m_date = date2years(df[~pd.isna(df[params.date_col])][params.date_col].min())[1]
    M_date = date2years(df[~pd.isna(df[params.date_col])][params.date_col].max())[2]
    df[['date', 'lower', 'upper']] = df[params.date_col].apply(lambda _: date2years(_, None, m_date, M_date)).apply(
        pd.Series)
    df.loc[pd.isna(df['date']), 'date'] = 'b(' + df.loc[pd.isna(df['date']), 'lower'].astype(str) \
                                          + ',' + df.loc[pd.isna(df['date']), 'upper'].astype(str) + ')'
    if params.dates:
        with open(params.dates, 'w+') as f:
            f.write('%d\n' % df.shape[0])
        df['date'].to_csv(params.dates, sep='\t', header=False, mode='a')


import pandas as pd
import numpy as np
import math
import datetime
import matplotlib.pyplot as plt
from matplotlib import style
import detrendPrice
import WhiteRealityCheckFor1

# from Data_ingestion_Rot_Momentum import *
import yfinance as yf

yf.pdr_override()

def getDate(dt):
    if type(dt) != str:
        return dt
    try:
        datetime_object = datetime.datetime.strptime(dt, "%Y-%m-%d")
    except Exception:
        datetime_object = datetime.datetime.strptime(dt, "%m/%d/%Y")
        return datetime_object
    else:
        return datetime_object

# All COLUMN_NAMES are capitalized
# IMPORTANT: ALL ETF LISTS  MUST END WITH SHY (or equivalent) ETF (=rightmost column of the dataframe)
# SHY equivalent = a bond ETF
# dfP are the prices, used for the calculation of trading signals
# dfAP are the adjusted prices, used for the calculation of portfolio returns

dfP = pd.read_csv(
    "VSC.TO.VSB.TO.ZIC.TO.HBB.TO.TDB.TO.XBB.TO.XGB.TO.csv", parse_dates=["Date"]
)
dfAP = pd.read_csv(
    "VSC.TO.VSB.TO.ZIC.TO.HBB.TO.TDB.TO.XBB.TO.XGB.TO_AP.csv", parse_dates=["Date"]
)

dfP = dfP.sort_values(by="Date")
dfAP = dfAP.sort_values(by="Date")
dfP.set_index("Date", inplace=True)
dfAP.set_index("Date", inplace=True)

# logReturns = 1 means log returns will be used in the calculation of portfolio returns, 0 means pct_changes
# Aperiods = lookback, determines what counts as the short term period, 20 days is the Default setting
# the selection of the ETF is based on maximum weighted score of:

# A returns, or returns in the short term period

# B returns, or returns in the longer term period (here set to 3 times the short term period)

# volatility, or volatility in the short term period.

# Frequency= holding period, how long to wait to rebalance, 18W-FRI is the Default setting for SPY-TLT combination.
# The frequency of a given ETF list can be determined by generating a Sharpe surface, assuming Fridays is the best trading day.

# Frequency="B" every business day, "D" every calendar day; "10B" means every 10 business days ("2B" is the minimum)
# Frequency="W" every weeek, "2W" for every 2 weeks, "3W" every 3 weeks etc
# Frequency="W-TUE" every Tuesday, "2W-TUE" for every 2 Tuesdays, "3W-TUE" every 3 Tuesdays etc
# Frequency= "BM" every month, "2BM" for every 2 months, "3BM" every 3 months etc; B relates to business days; 31 or previous business day if necessary
# Frequency="SM" on the middle (15) and end (31) of the month, or previous business day if necessary

# Delay = 1 if the trade occurs instantaneously with the signal, 2 if the trade occurs 1 day after the signal

# ShortTermWeight = the weight of short term returns, .3 by default
# LongTermWeight = the weight of long term returns, .4 by default
# ShortTermVolatilityWeight = the weight of short term volatility, .4
# ShortTermWeight+LongTermWeight+ShortTermVolatilityWeight should add up to 1.

# other parameters (experimental)
# Cash Filter = 0 (or 1) forces the portfolio to invest in whatever ETF in the list "StandsForCash"
# MAperiods = moving average, usually 200, that prices have to be above of to allow trading, if the cash filter is set to 1.
# StandsForCash = "TLT" #what the system invests in when the CashFilter is triggered, the rightmost ETF in the dataframe
# if you set cash filter to 1, you need to identify what ETF StandsForCash (should be the rightmost ETF in the dataframe)
# Zboundary = -1.5 #alternative cash filter (but need understand and to uncomment line: alternative cash filter)
# Zperiods = 200  #alternative cash filter  (but need understand and to uncomment line: alternative cash filter)
# momentum = 1 means A and B returns are ranked in increasing order (momentum), 0 in decreasing order (reversion to the mean)
# volmomentum = 1 volatility ranked in increasing order (momentum), 0 in decreasing order (reversion to the mean)

logReturns = 0
Aperiods = 8 * 5  # Lookback 20 Default
Frequency = "18W-FRI"  # fridays and thursdays are the best trading days
ShortTermWeight = 0.3
LongTermWeight = 0.4
ShortTermVolatilityWeight = 0.4
Delay = 1

# experimental cash filter
CashFilter = 0
MAperiods = 200
StandsForCash = "SHY"
Zboundary = -1.5
Zperiods = 200

# experimental mean reversion trading
momentum = 1
volmomentum = 0  # do not change

# lookbacks for longer term period and volatily
Bperiods = 3 * Aperiods + ((3 * Aperiods) // 20) * 2  # 66 Default
Speriods = Aperiods  # 20 Default

# dfA contains a short moving average of the daily percent changes, calculated for each ETF
# dfB contains a long moving average of the daily percent changes, calculated for each ETF
# dfS contains the annualized volatility, calculated for each ETF
# dfMA contains 200 MA of price
# dfDetrend contains the detrended AP prices (for White's reality test)

dfA = dfP.drop(labels=None, axis=1, columns=dfP.columns)
dfB = dfP.drop(labels=None, axis=1, columns=dfP.columns)
dfS = dfP.drop(labels=None, axis=1, columns=dfP.columns)
dfZ = dfP.drop(labels=None, axis=1, columns=dfP.columns)
dfMA = dfP.drop(labels=None, axis=1, columns=dfP.columns)
dfDetrend = dfP.drop(labels=None, axis=1, columns=dfP.columns)

# calculating the three performance measures in accordance with their windows

dfA = dfP.pct_change(
    periods=Aperiods - 1, fill_method="pad", limit=None, freq=None
)  # is counting window from 0
dfB = dfP.pct_change(
    periods=Bperiods - 1, fill_method="pad", limit=None, freq=None
)  # is counting window from 0
dfR = dfP.pct_change(
    periods=1, fill_method="pad", limit=None, freq=None
)  # is counting window from 0

columns = dfP.shape[1]
for column in range(columns):
    dfS[dfP.columns[column]] = (
        dfR[dfP.columns[column]].rolling(window=Speriods).std()
    ) * math.sqrt(252)
    dfZ[dfP.columns[column]] = (
        dfP[dfP.columns[column]]
        - dfP[dfP.columns[column]].rolling(window=Zperiods).mean()
    ) / dfP[dfP.columns[column]].rolling(window=Zperiods).std()
    dfMA[dfP.columns[column]] = (
        dfP[dfP.columns[column]].rolling(window=MAperiods).mean()
    )
    dfDetrend[dfAP.columns[column]] = detrendPrice.detrendPrice(
        dfAP[dfAP.columns[column]]
    ).values

# Ranking each ETF w.r.t. short moving average of returns
dfA_ranks = dfP.copy(deep=True)
dfA_ranks[:] = 0

columns = dfA_ranks.shape[1]
rows = dfA_ranks.shape[0]

# this loop takes each row of the A dataframe, puts the row into an array,
# within the array the contents are ranked,
# then the ranks are placed into the A_ranks dataframe one by one
for row in range(rows):
    arr_row = dfA.iloc[row].values
    if momentum == 1:
        temp = arr_row.argsort()  # sort momentum, best is ETF with largest return
    else:
        temp = (-arr_row).argsort()[
            : arr_row.size
        ]  # sort reversion, best is ETF with lowest return
    ranks = np.empty_like(temp)
    ranks[temp] = np.arange(1, len(arr_row) + 1)
    for column in range(columns):
        dfA_ranks.iat[row, column] = ranks[column]

dfB_ranks = dfP.copy(deep=True)
dfB_ranks[:] = 0

columns = dfB_ranks.shape[1]
rows = dfB_ranks.shape[0]

# this loop takes each row of the B dataframe, puts the row into an array,
# within the array the contents are ranked,
# then the ranks are placed into the B_ranks dataframe one by one
for row in range(rows):
    arr_row = dfB.iloc[row].values
    if momentum == 1:
        temp = arr_row.argsort()  # sort momentum
    else:
        temp = (-arr_row).argsort()[: arr_row.size]  # sort reversion
    ranks = np.empty_like(temp)
    ranks[temp] = np.arange(1, len(arr_row) + 1)
    for column in range(columns):
        dfB_ranks.iat[row, column] = ranks[column]

dfS_ranks = dfP.copy(deep=True)
dfS_ranks[:] = 0

columns = dfS_ranks.shape[1]
rows = dfS_ranks.shape[0]

# this loop takes each row of the dfS dataframe, puts the row into an array,
# within the array the contents are ranked,
# then the ranks are placed into the dfS_ranks dataframe one by one
for row in range(rows):
    arr_row = dfS.iloc[row].values
    if volmomentum == 1:
        temp = arr_row.argsort()  # sort momentum, best is highest volatility
    else:
        temp = (-arr_row).argsort()[
            : arr_row.size
        ]  # sort reversion, best is lowest volatility
    ranks = np.empty_like(temp)
    ranks[temp] = np.arange(1, len(arr_row) + 1)
    for column in range(columns):
        dfS_ranks.iat[row, column] = ranks[column]

#################################################################################################################
# Weights of the varous ranks ####################################################################################
dfA_ranks = dfA_ranks.multiply(ShortTermWeight)  # .3 default
dfB_ranks = dfB_ranks.multiply(LongTermWeight)  # .4 default
dfS_ranks = dfS_ranks.multiply(ShortTermVolatilityWeight)  # .3 default
dfAll_ranks = dfA_ranks.add(dfB_ranks, fill_value=0)
dfAll_ranks = dfAll_ranks.add(dfS_ranks, fill_value=0)
#################################################################################################################
#################################################################################################################

# Choice is the dataframe where the ETF with the maximum score is identified
dfChoice = dfP.copy(deep=True)
dfChoice[:] = 0
rows = dfChoice.shape[0]

# this loop takes each row of the All-ranks dataframe, puts the row into an array,
# within the array the contents scanned for the maximum element
# then the maximum element is placed into the Choice dataframe
for row in range(rows):
    arr_row = dfAll_ranks.iloc[row].values
    if momentum == 0 or CashFilter == 1:
        arr_row = arr_row[
            0 : len(arr_row) - 1
        ]  # don't rank SHY (the rightmost column) if doing reversion to mean trading or if requested to ignore it
    max_arr_column = np.argmax(arr_row, axis=0)  # gets the INDEX of the max
    if CashFilter == 1:
        if (
            dfP[dfP.columns[max_arr_column]][row]
            >= dfMA[dfMA.columns[max_arr_column]][row]
        ):  # "200MA" condition for cash filter
            # if (dfZ[dfZ.columns[max_arr_column]][row] > Zboundary): #alternative cash filter
            dfChoice.iat[row, max_arr_column] = 1
        else:
            dfChoice.iat[row, dfP.columns.get_loc(StandsForCash)] = 1
    else:
        dfChoice.iat[row, max_arr_column] = 1

# dfPRR is the dataframe containing the log or pct_change returns of the ETFs
# will be based on adjusted prices rather than straight prices

if logReturns == 1:
    dfPLog = dfAP.apply(np.log)
    dfPLogShift = dfPLog.shift(1)
    dfPRR = dfPLog.subtract(dfPLogShift, fill_value=0)
    # repeat with detrended prices
    dfPLog = dfDetrend.apply(np.log)
    dfPLogShift = dfPLog.shift(1)
    dfDetrendRR = dfPLog.subtract(dfPLogShift, fill_value=0)

else:
    dfPRR = dfAP.pct_change()
    dfDetrendRR = dfDetrend.pct_change()

# T is the dataframe where the trading day is calculated.

dfT = dfP.drop(labels=None, axis=1, columns=dfP.columns)
columns = dfP.shape[1]
for column in range(columns):
    new = dfP.columns[column] + "_CHOICE"
    dfPRR[new] = pd.Series(np.zeros(rows), index=dfPRR.index)
    dfPRR[new] = dfChoice[dfChoice.columns[column]]

dfT["DateCopy"] = dfT.index
dfT1 = dfT.asfreq(freq=Frequency, method="pad")
dfT1.set_index("DateCopy", inplace=True)
dfTJoin = pd.merge(
    dfT, dfT1, left_index=True, right_index=True, how="outer", indicator=True
)

dfTJoin = dfTJoin.loc[
    ~dfTJoin.index.duplicated(keep="first")
]  # eliminates a row with a duplicate index which arises when using kibot data
dfPRR = pd.merge(dfPRR, dfTJoin, left_index=True, right_index=True, how="inner")
dfPRR.rename(columns={"_merge": Frequency + "_FREQ"}, inplace=True)
# dfPRR[Frequency+"_FREQ"] = dfTJoin["_merge"] #better to do this with merge as above

# _LEN means Long entry for that ETF
# _NUL means number units long of that ETF
# _LEX means long exit for that ETF
# _R means returns of that ETF (traded ETF)
# _ALL_R means returns of all ETFs traded, i.e. portfolio returns
# CUM_R means commulative returns of all ETFs, i.e. portfolio cummulative returns

columns = dfP.shape[1]
for column in range(columns):
    new = dfP.columns[column] + "_LEN"
    dfPRR[new] = (dfPRR[Frequency + "_FREQ"] == "both") & (
        dfPRR[dfP.columns[column] + "_CHOICE"] == 1
    )
    new = dfP.columns[column] + "_LEX"
    dfPRR[new] = (dfPRR[Frequency + "_FREQ"] == "both") & (
        dfPRR[dfP.columns[column] + "_CHOICE"] != 1
    )
    new = dfP.columns[column] + "_NUL"
    dfPRR[new] = np.nan
    dfPRR.loc[
        dfPRR[dfP.columns[column] + "_LEX"] == True, dfP.columns[column] + "_NUL"
    ] = 0
    dfPRR.loc[
        dfPRR[dfP.columns[column] + "_LEN"] == True, dfP.columns[column] + "_NUL"
    ] = 1  # this order is important
    dfPRR.iat[0, dfPRR.columns.get_loc(dfP.columns[column] + "_NUL")] = 0
    dfPRR[dfP.columns[column] + "_NUL"] = dfPRR[dfP.columns[column] + "_NUL"].fillna(
        method="pad"
    )
    new = dfP.columns[column] + "_R"
    dfPRR[new] = dfPRR[dfP.columns[column]] * dfPRR[dfP.columns[column] + "_NUL"].shift(
        Delay
    )
    # repeat for detrended returns
    dfDetrendRR[new] = dfDetrendRR[dfP.columns[column]] * dfPRR[
        dfP.columns[column] + "_NUL"
    ].shift(Delay)

# calculating all returns
dfPRR = dfPRR.assign(ALL_R=pd.Series(np.zeros(rows)).values)
# repeat for detrended returns
dfDetrendRR = dfDetrendRR.assign(ALL_R=pd.Series(np.zeros(rows)).values)

# the return of the portfolio is a sequence of returns made
# by appending sequences of returns of traded ETFs
# Since non traded returns are multiplied by zero, we only need to add the columns
# of the returns of each ETF, traded or not
columns = dfP.shape[1]
for column in range(columns):
    dfPRR["ALL_R"] = dfPRR["ALL_R"] + dfPRR[dfP.columns[column] + "_R"]
    # repeat for detrended returns
    dfDetrendRR["ALL_R"] = (
        dfDetrendRR["ALL_R"] + dfDetrendRR[dfP.columns[column] + "_R"]
    )

dfPRR = dfPRR.assign(DETREND_ALL_R=dfDetrendRR["ALL_R"])

# dfPRR['CUM_R'] = dfPRR['ALL_R'].cumsum()  #this is good only for log returns
# dfPRR['CUM_R'] = dfPRR['CUM_R'] + 1 #this is good only for log returns

# calculating portfolio investment column in a separate dataframe, using 'ALL_R' = portfolio returns

dfPRR = dfPRR.assign(I=np.cumprod(1 + dfPRR["ALL_R"]))  # this is good for pct return
dfPRR.iat[0, dfPRR.columns.get_loc("I")] = 1
# repeat for detrended returns
dfDetrendRR = dfDetrendRR.assign(
    I=np.cumprod(1 + dfDetrendRR["ALL_R"])
)  # this is good for pct return
dfDetrendRR.iat[0, dfDetrendRR.columns.get_loc("I")] = 1

dfPRR = dfPRR.assign(DETREND_I=dfDetrendRR["I"])

try:
    sharpe = (dfPRR["ALL_R"].mean() / dfPRR["ALL_R"].std()) * math.sqrt(252)
except ZeroDivisionError:
    sharpe = 0.0

style.use("fivethirtyeight")
dfPRR["I"].plot()
plt.legend()
plt.show()
# plt.savefig(r'Results\%s.png' %(title))
# plt.close()

start = 1
start_val = start
end_val = dfPRR["I"].iat[-1]

start_date = getDate(dfPRR.iloc[0].name)
end_date = getDate(dfPRR.iloc[-1].name)
days = (end_date - start_date).days

TotaAnnReturn = (end_val - start_val) / start_val / (days / 360)
TotaAnnReturn_trading = (end_val - start_val) / start_val / (days / 252)

CAGR_trading = round(
    ((float(end_val) / float(start_val)) ** (1 / (days / 252.0))).real - 1, 4
)  # when raised to an exponent I am getting a complex number, I need only the real part
CAGR = round(
    ((float(end_val) / float(start_val)) ** (1 / (days / 350.0))).real - 1, 4
)  # when raised to an exponent I am getting a complex number, I need only the real part

print("TotaAnnReturn = %f" % (TotaAnnReturn * 100))
print("CAGR = %f" % (CAGR * 100))
print("Sharpe Ratio = %f" % (round(sharpe, 2)))

# Detrending Prices and Returns
WhiteRealityCheckFor1.bootstrap(dfPRR["DETREND_ALL_R"])

dfPRR.to_csv(r"Results\dfPRR.csv", header=True, index=True, encoding="utf-8")


# flat files - .txt or .csv
# The Most Basic importing technique
file = open("dataset/moby_dick.txt", 'r')
# print(file.read())
file.close()

file = open("dataset/cars.csv", 'r')
# print(file.read())
file.close()

# The Intermediate Approach
with open("dataset/moby_dick.txt") as file:
	d = file.read()
# print(d)

with open("dataset/cars.csv") as file:
	d = file.readline()
# print(d)

# The Standard Approach (Using numpy)
# loadtxt(): (Only numerical data allowed)
import numpy as np
data = np.loadtxt("dataset/digits.csv", delimiter=',')
# print(data)

data = np.loadtxt("dataset/seaslug.txt", delimiter='\t', dtype=str)
# print(data[0])

data_float = np.loadtxt("dataset/seaslug.txt", delimiter='\t', dtype=float, skiprows=1)
# print(data_float)

data_all_types = np.genfromtxt("dataset/titanic.csv", delimiter=',', dtype=None, names=True)
# data_all_types = np.recfromcsv("dataset/titanic.csv")
# print(data_all_types[:3])

# The Standard Approach (Using pandas)
import pandas as pd
data = pd.read_csv("dataset/titanic.csv",nrows=5, na_values='Nothing')
# print(data.head())

# data_array = np.array(data)
# print(data)

# Excel Files
import pandas as pd
file = "dataset/battledeath.xlsx"
data = pd.ExcelFile(file)
# print(data.sheet_names)

# data1 = data.parse('2004')
# data1 = data.parse(1)
data1 = data.parse(1, usecols=[1], skiprows=[], names=['Year'])
# print(data1.head())

# SAS Files
from sas7bdat import SAS7BDAT
with SAS7BDAT("dataset/sales.sas7bdat") as file:
	d = file.to_data_frame()
# print(d.head())

# Stata Files
import pandas as pd
data = pd.read_stata("dataset/disarea.dta")
# print(data.head())

# HDf5
import h5py
data = h5py.File("dataset/LIGO_data.hdf5", 'r')
print(data.keys())
for key in data['meta'].keys():
	print(key)
print(data['meta']['Detector'].value)

# Mat files
import scipy.io
mat = scipy.io.loadmat('dataset/ja_data2.mat')
print(mat.keys())


import os
import pathlib
from os.path import join

import numpy as np

data_folder = pathlib.Path(join(os.getcwd(), "mat-data"))
arm_folder = pathlib.Path(join(os.getcwd(), "arm-data"))
rna_folder = pathlib.Path(join(os.getcwd(), 'rna'))
fig_folder = pathlib.Path(join(os.getcwd(), "figures"))

# Used to calculate features
num_threads = 6

signals = ['BPSK',
           'QPSK',
           'PSK8',
           'QAM16',
           'QAM64',
           'noise']

signals_labels = [0, 1, 2, 3, 4, 5]

# Dictionary to access variable inside MAT file
mat_info = {'BPSK': 'signal_bpsk',
            'QPSK': 'signal_qpsk',
            'PSK8': 'signal_8psk',
            'QAM16': 'signal_qam16',
            'QAM64': 'signal_qam64',
            'noise': 'signal_noise'}

SNR_values = {0: '-10',
              1: '-8',
              2: '-6',
              3: '-4',
              4: '-2',
              5: '0',
              6: '2',
              7: '4',
              8: '6',
              9: '8',
              10: '10',
              11: '12',
              12: '14',
              13: '16',
              14: '18',
              15: '20'}

training_SNR = np.int8(np.linspace(11, 15, 5))
testing_SNR = np.int8(np.linspace(0, 15, 16))
frame_size = 2048
number_of_testing_frames = 500
number_of_training_frames = 5000

# Load dataset from MATLAB
features_files = [f + "_features" for f in signals]
testing_features_files = [f + "_features_testing" for f in signals]

features_names = {
    0: "Std of the Instantaneous Phase",
    1: "Std of the Absolute Instantaneous Phase",
    2: "Std of the Instantaneous Frequency",
    3: "Std of the Absolute Instantaneous Frequency",
    4: "Std of the CN Instantaneous Amplitude",
    5: "Std of the Absolute CN Instantaneous Amplitude",
    6: "Mean Value of the Signal Magnitude",
    7: "Squared Mean of the Signal Magnitude",
    8: "Normalized Sqrt Value of Sum of Amplitude",
    9: "Ratio of I/Q Components",
    10: "Gmax",
    11: "Kurtosis of the Absolute Value",
    12: "Kurtosis of the Absolute Frequency",
    13: "Cumulant Order 20",
    14: "Cumulant Order 21",
    15: "Cumulant Order 40",
    16: "Cumulant Order 41",
    17: "Cumulant Order 42",
    18: "Cumulant Order 60",
    19: "Cumulant Order 61",
    20: "Cumulant Order 62",
    21: "Cumulant Order 63"
}

used_features = [
    3,
    5,
    6,
    11,
    15,
    17
]

features_functions = {
    0: "functions.std_dev_inst_phase(signal_input)",
    1: "functions.std_dev_abs_inst_phase(signal_input)",
    2: "functions.std_dev_inst_freq(signal_input)",
    3: "functions.std_dev_abs_inst_freq(signal_input)",
    4: "functions.std_dev_inst_cna(signal_input)",
    5: "functions.std_dev_abs_inst_cna(signal_input)",
    6: "functions.mean_of_signal_magnitude(signal_input)",
    7: "functions.squared_mean_of_signal_magnitude(signal_input)",
    8: "functions.normalized_sqrt_of_sum_of_amp(signal_input)",
    9: "functions.ratio_iq(signal_input)",
    10: "functions.gmax(signal_input)",
    11: "functions.kurtosis_of_abs_amplitude(signal_input)",
    12: "functions.kurtosis_of_abs_freq(signal_input)",
    13: "functions.cumulant_20(signal_input)",
    14: "functions.cumulant_21(signal_input)",
    15: "functions.cumulant_40(signal_input)",
    16: "functions.cumulant_41(signal_input)",
    17: "functions.cumulant_42(signal_input)",
    18: "functions.cumulant_60(signal_input)",
    19: "functions.cumulant_61(signal_input)",
    20: "functions.cumulant_62(signal_input)",
    21: "functions.cumulant_63(signal_input)"
}

number_of_used_features = len(used_features)
used_features_names = []
for feature in used_features:
    used_features_names.append(features_names[feature])

# Calculate range of fixed point numbers #QM.N
q_range = {}
resolution = []
for M in range(0, 7):
    N = 15 - M
    k = "Q{}.{}".format(M, N)
    q_range[k] = ([-2 ** (M - 1), 2 ** (M - 1) - 2 ** (-N)])
    resolution.append(2 ** (-N))