# Import Modules & Functions
import pandas as pd
from pandas import DataFrame
from pandas import read_csv, read_excel
from pandas import Series
from numpy import log
from statistics import stdev
from datetime import date, timedelta, datetime
import time
import requests
import threading
from threading import Timer, Event, Thread
import json


#Importing Modules, setting starting parameters and defining classes

# The class to create an object for every isin and to keep the live information of it.
class Isin:
    def __init__(self, name):
        # isin's name
        self.name= name
        # This is the Persian symbol of the isin.
        self.persian_id= ''
        #The bourse id to crawl from the tsetmc
        self.bourse_id= ''
        
        #This part sets the initial parameters. They will be adjusted if the isin is in the continous run.
        # This fixes the activation status of the isin.
        self.activate= True
        # The free budget of the isin: 
        self.budget= 0
        # This is servers's time Ud
        self.server_time= None
        # The lastTrade Time Ud
        self.lastTrade_Time= None
        self.Old_lastTrade = None
        # This shows the state of the Stockwatch data. Ud
        self.state= None
        # This represents the last Mean Reversion Test result. Ud
        self.MR_Test= False
        # This is the half life of mean reversion if MR_Test is True and 0 if not. Ud
        self.half_life_number= 0
        # This event is normally None, Buy in Buy-position and Sell in Sell-position.
        self.event= None
        # This is False when we don't hold any share of the isin and True if we hold a share.
        self.Hold= False
        # This shows the volume of the share of the isin we hold at the moment.
        self.HoldVolume= 0
        # This is the last price recorded in the market. Ud
        self.Last_Price= 0
        # This is to check if the commision condition is accuired according to standard deviation and expected return. UD
        self.Commission_Cond= False
        # This shows the instantanous Mouving Average Ud
        self.SMA= 0
        # This calculates the Buy Limit for Enter function according to SMA and st_dev. Ud
        self.Buy_Limit= 0
        # This is Benefit limit to sell the shares of the isin. Ud
        self.Ben_Limit= 0
        # This is Loss Limit to sell the shares of the isin. Ud
        self.Loss_Limit= 0
        # This is the standard deviation of the last price records.  Ud
        self.st_dev= 0 

def Create_isin_object(isn):
    return Isin(isn)


#The Class to repeat a function as threading module every n seconds
class RepeatedTimer:

    """Repeat `function` every `interval` seconds."""

    def __init__(self, interval, function, *args, **kwargs):
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.start = time.time()
        self.event = Event()
        self.thread = Thread(target=self._target)
        self.thread.start()

    def _target(self):
        while not self.event.wait(self._time):
            self.function(*self.args, **self.kwargs)

    @property
    def _time(self):
        return self.interval - ((time.time() - self.start) % self.interval)

    def stop(self):
        self.event.set()
        self.thread.join()

def Repeat_Function(interval, function, *args, **kwargs):
    RepeatedTimer(interval, function, *args, **kwargs)
    
# What about stopping a function?

# Getting StockWatch data

def TSE_Close_Daily(bourse_id):
    url_daily_data_tsetmc= 'http://tsetmc.com/tsev2/data/Export-txt.aspx?t=i&a=1&b=0&i=???'
    url_daily_data= url_daily_data_tsetmc.replace('i=???', 'i='+ bourse_id)
    daily_data= requests.get(url_daily_data)
    daily_data= read_csv(io.StringIO(daily_data.text))
    daily_data= pd.DataFrame(daily_data)
    daily_data= daily_data['<CLOSE>'].values
    #daily_data= daily_data[::_frequency]
    daily_data= daily_data[::-1]
    return daily_data
    #daily_data= pd.DataFrame(daily_data, columns= ['Close'])
    #return daily_data

def dataengine_Data(isn, number_of_records, _frequency):
    _number_of_records= 10 * number_of_records * _frequency
    'https://omid.algo.ir/api/dataengine/candle/minutely?isin=IRO1TMLT0001&page=0&size=100&from=2020-06-24&to=2020-07-08'
    url_SW_dataengine = 'https://omid.algo.ir/api/dataengine/candle/_period?isin=??&page=0&size=???&from=???&to=???'
    # Fixing of the parameters of the request to dataengine api
    DAYS= _number_of_records//180 +5
    Beginning_Date= datetime.today() + timedelta(days=-DAYS)
    Beginning_Date= Beginning_Date.strftime('%Y-%m-%d')
    Tomorrow_Date= datetime.today() + timedelta(days=1)
    Tomorrow_Date= Tomorrow_Date.strftime('%Y-%m-%d')
    url_SW_dataengine= url_SW_dataengine.replace('_period', 'minutely')
    url_SW_dataengine= url_SW_dataengine.replace('isin=??', 'isin='+ isn)
    url_SW_dataengine= url_SW_dataengine.replace('size=???', 'size=' + str(_number_of_records))
    url_SW_dataengine= url_SW_dataengine.replace('from=???', 'from='+ Beginning_Date)
    url_SW_dataengine= url_SW_dataengine.replace('to=???', 'to='+ Tomorrow_Date)
    # sending the request and processing the response
    for i in range(1,100):
        try:
            data_SW_dataengine = requests.get(url = url_SW_dataengine)
            break
        except OSError:
            sleep(1)
    data_SW_dataengine = data_SW_dataengine.json()['content']
    data_SW_dataengine = pd.DataFrame.from_dict(data_SW_dataengine)
    try:
        data_SW_dataengine= data_SW_dataengine['closePrice']
    except:
        return
    data_SW_dataengine= data_SW_dataengine[::_frequency]
    data_SW_dataengine= data_SW_dataengine[len(data_SW_dataengine) - number_of_records: ]
    # changing the close price to a list, applying _frequency, getting the last records, and changing to a DataFrame.
    data_SW_dataengine= data_SW_dataengine.values
    
    #data_SW_dataengine= pd.DataFrame(data_SW_dataengine, columns= ['last'])
    return data_SW_dataengine
    
# This function gets the Stockwatch data from omid core api and returns it as a one row Data Frame
def Get_SW_Data(isn, Maximum_Permitted_Delay):
    url_SW= 'https://omid.algo.ir/api/core/stockwatch/isn=??'
    TimeFormat= '%Y-%m-%d %H:%M:%S'
    url_SW_UD= url_SW
    url_SW_UD= url_SW_UD.replace('isn=??', isn)
    for i in range (1,Maximum_Permitted_Delay):
        try:
            Data_SW_UD = requests.get(url = url_SW_UD)
        except OSError:
            sleep(1)
            if i== Maximum_Permitted_Delay - 1:
                return None
    Data_SW= Data_SW_UD.content.decode("utf-8")
    try:
        Data_SW= ast.literal_eval(Data_SW)
    except:
        return None
    Data_SW= pd.DataFrame([Data_SW])
    dateTime= pd.to_datetime(Data_SW.loc[0,'dateTime'])
    lastTrade= pd.to_datetime(Data_SW.loc[0,'lastTrade'])
    currentTime= pd.to_datetime(datetime.now().strftime(TimeFormat))
    dateTimeDelay= (currentTime - dateTime).total_seconds()
    lastTradeDelay= (currentTime - lastTrade).total_seconds()
    if (dateTimeDelay > Maximum_Permitted_Delay):
        return 'Delay in data'
    elif (lastTradeDelay > Maximum_Permitted_Delay):
        return None
    return Data_SW

# This function gets the BidAsk data from omid.algo.ir/api/core  and returns it as a five row Data Frame and returns None in case of exception or delay in case of dalay in information. 

def Get_BidAsk_Data(isn, Maximum_Permitted_Delay):
    url_BidAsk= 'https://omid.algo.ir/api/core/bidask/isn=??'
    TimeFormat= '%Y-%m-%d %H:%M:%S'
    url_BidAsk_UD= url_BidAsk
    url_BidAsk_UD= url_BidAsk_UD.replace('isn=??', isn)
    for i in range (1,60):
        try:
            Data_BidAsk_UD = requests.get(url = url_BidAsk_UD)
        except OSError:
            sleep(1)
    Data_BidAsk= Data_BidAsk_UD.content.decode("utf-8")
    try:
        Data_BidAsk= ast.literal_eval(Data_BidAsk)
    except:
        return None
    BidAsk_dateTime= pd.to_datetime(Data_BidAsk["dateTime"])  
    Data_BidAsk= Data_BidAsk["items"]
    Data_BidAsk= pd.DataFrame(Data_BidAsk)
    currentTime= pd.to_datetime(datetime.now().strftime(TimeFormat))
    dateTimeDelay= (currentTime - BidAsk_dateTime).total_seconds()
    if (dateTimeDelay > Maximum_Permitted_Delay):
        return 'Delay in BidAsk data'
    return Data_BidAsk

def is_SW_online(isn, Maximum_Permitted_Delay):
    TimeFormat= '%Y-%m-%d %H:%M:%S'
    currentTime= pd.to_datetime(datetime.now().strftime(TimeFormat))
    New_Data= Get_SW_Data(isn, Maximum_Permitted_Delay)
    # This is server's time
    server_time= New_Data.loc[0,'dateTime']
    if (currentTime - pd.to_datetime(server_time)).total_seconds() > Maximum_Permitted_Delay:
        return False
    else:
        return True
    
def is_trade_time():
    TimeFormat= '%Y-%m-%d %H:%M:%S'
    # Begin & End Time of the Market
    Begin_Time= '09:00:00'
    End_Time= '12:30:00'
    currentTime= pd.to_datetime(datetime.now().strftime(TimeFormat))
    BeginTime= pd.to_datetime(Begin_Time)
    EndTime= pd.to_datetime(End_Time)
    if  (currentTime - BeginTime).total_seconds() < 0 or (EndTime - currentTime).total_seconds() < 0 :
        return False
    else:
        return True
    
def Send_Order(account_user, account_password, user_Id, isn, Price, Volume, side):
    return
    #account_user= "azadifaraz"
    #account_password= "123456$aA"
    #user_Id= "bfdacd8a-0ae7-4897-8f2f-0300d94025eb"
    url_token = "https://omid.algo.ir/api/omid/user/login-without-captcha"
    url_order = "https://omid.algo.ir/api/omid/order"
    _account_user= "\"" + account_user + "\""
    _account_password= "\"" + account_password + "\""
    _user_Id= "\"" + user_Id + "\""
    _side= "\"" + side + "\""
    
    payload="{\n    \"userName\":"+ _account_user + ",\n    \"password\":"+ _account_password + ",\n    \"token\":\"\",\n    \"captcha\":\"\"\n}" 
    headers = {  'Content-Type': 'application/json'}
    response = requests.request("POST", url_token, headers=headers, data=payload)
    print(response.json())
    token= response.json()['token']
    
    price= Price
    quantity= Volume
    _isn= "\""+ isn + "\""
    payload="{\n    \"isin\":" +_isn + ",\n    \"userId\":"+  _user_Id + ",\n    \"price\":"+ str(price) + ",\n    \"quantity\": "+ str(quantity) +",\n    \"validity\": \"FILL_AND_KILL\",\n    \"side\":" + _side + "\n}"
    headers = {  'Token': token,  'Content-Type': 'application/json'}
    response = requests.request("POST", url_order, headers=headers, data=payload)
    message= response.json()["message"]
    print(message)
    print ('OK!')
    return     
    