Exemple #1
0
def Reset(*_):
    print('---------------------\nReset\n---------------------')
    global mornitorFilePath
    global transacFilePath
    if not os.path.exists(mornitorFilePath):
        return None
    m_df = pd.read_csv(mornitorFilePath)
    t_df = pd.read_csv(transacFilePath)
    deleteList = []

    m_user_list = m_df['User'].unique().tolist()
    t_user_list = t_df['User'].unique().tolist()
    for user in m_user_list:
        print('Checking User {} in Mornitor {}'.format(user, m_user_list))
        if not user in list(configJson):
            deleteList.append(user)
    for user in t_user_list:
        print('Checking User {} in Transaction {}'.format(user, t_user_list))
        if not user in list(configJson):
            deleteList.append(user)

    #Sending Restart
    for user in list(configJson):
        systemName = configJson[user]['system']
        if bool(configJson[user]['reset']):
            gSheet.setValue('Config',
                            findKey='idName',
                            findValue=user,
                            key='reset',
                            value=0)
            gSheet.setValue('Config',
                            findKey='idName',
                            findValue=user,
                            key='lastReport',
                            value=time.time())
            text = '[ Reset Portfoilo ]\n' +\
                   'User ID : {} \n'.format(user) +\
                   'Preset ID : {} \n'.format(configJson[user]['preset']) +\
                   'System ID : {} \n'.format(systemName) +\
                   'Size : {} \n'.format(systemJson[systemName]['size']) +\
                   'Target Profit : {}%'.format(systemJson[systemName]['percentageProfitTarget'])
            lineNotify.sendNotifyMassage(configJson[user]['lineToken'], text)
            print(text)

    for user in deleteList:
        print('delete [ {} ]'.format(user))
        m_df = m_df[m_df['User'] != user]
        t_df = t_df[t_df['User'] != user]

    m_df.to_csv(mornitorFilePath, index=False)
    t_df.to_csv(transacFilePath, index=False)
    print('User Reset')
Exemple #2
0
def getBalance(idName):
    API_KEY = configJson[idName]['bk_apiKey']
    API_SECRET = configJson[idName]['bk_apiSecret']
    if API_KEY == '' or API_SECRET == '':
        print('this user have no API KEY or API SECRET to send order')
        return None
    bitkub = Bitkub()
    bitkub.set_api_key(API_KEY)
    bitkub.set_api_secret(API_SECRET)
    balance = bitkub.balances()
    data = {}
    if balance['error'] == 0:
        for sym in balance['result']:
            if balance['result'][sym]['available'] > 0:
                available = balance['result'][sym]['available']
                available_h = max([
                    available, configJson[idName]['available'],
                    configJson[idName]['availableHigh']
                ])
                p_drawdown = (abs(available_h - available) / available_h) * 100
                p_drawdown = round(p_drawdown, 2)
                data[sym] = {
                    'available': available,
                    'reserved': balance['result'][sym]['reserved']
                }
                #update balance data sheet
                if sym == 'THB':
                    gSheet.setValue('Config',
                                    findKey='idName',
                                    findValue=idName,
                                    key='available',
                                    value=available)
                    gSheet.setValue('Config',
                                    findKey='idName',
                                    findValue=idName,
                                    key='availableHigh',
                                    value=available_h)
                    gSheet.setValue('Config',
                                    findKey='idName',
                                    findValue=idName,
                                    key='percentageDrawdown',
                                    value=p_drawdown)
    return data
Exemple #3
0
def Realtime(idName, sendNotify=True):
    isActive = bool(configJson[idName]['active'])
    isActive = True
    isReset = bool(configJson[idName]['reset'])
    if isActive == False:
        return None
    print('---------------------\n[ {} ]  Monitoring\n---------------------'.
          format(idName))
    ticker = kbApi.getTicker()
    now = round(time.time())
    reportHourDuration = round(
        float(((now - configJson[idName]['lastReport']) / 60) / 60), 2)
    preset = configJson[idName]['preset']
    system = configJson[idName]['system']
    token = configJson[idName]['lineToken']
    portSize = int(configJson[idName]['portSize'])
    buySize = int(configJson[idName]['buySize'])
    profitTarget = float(configJson[idName]['percentageProfitTarget'])
    lossTarget = float(configJson[idName]['percentageLossTarget']) * (-1)
    triggerBuy = systemJson[system]['triggerBuy']
    triggerSell = systemJson[system]['triggerSell']
    triggerBuyPos = systemJson[system]['triggerBuyPosition']
    triggerSellPos = systemJson[system]['triggerSellPosition']
    adaptiveLoss = bool(configJson[idName]['adaptiveLoss'])
    print('Portfolio Size : {} | Buy Position Size : {}'.format(
        portSize, buySize))
    print('Buy : {} | Sell : {}'.format(triggerBuy, triggerSell))
    print('Trigger Buy : {} | Trigger Sell : {}'.format(
        triggerBuyPos, triggerSellPos))
    #print(ticker)

    colSelect = [
        'User', 'Symbol', 'Signal', 'Buy', 'Market', 'Profit%',
        'Max_Drawdown%', 'Change4HR%', 'Volume', 'BreakOut_H', 'BreakOut_MH',
        'BreakOut_M', 'BreakOut_ML', 'BreakOut_L', 'Low', 'High', 'Rec_Date',
        'Count'
    ]

    #Signal Dataframe
    signal_df = pd.read_csv(dataPath + '/signal.csv')
    signal_df = signal_df[
        (signal_df['Rec_Date'] == signal_df['Rec_Date'].max())
        & (signal_df['Preset'] == preset)]
    signal_df.sort_values(['Change4HR%', 'Volume', 'Risk%'],
                          ascending=[True, False, True])
    signal_df.reset_index(inplace=True)

    # New Column For Signal DF
    signal_df['User'] = idName
    signal_df['Buy'] = signal_df['Close']
    signal_df['Market'] = signal_df['Close']
    signal_df['Profit%'] = (
        (signal_df['Market'] - signal_df['Buy']) / signal_df['Buy']) * 100
    signal_df['Max_Drawdown%'] = 0.0
    signal_df['Count'] = 1
    for sym in ticker:
        signal_df.loc[(signal_df['Symbol'] == sym),
                      'Buy'] = ticker[sym]['last']
        signal_df.loc[(signal_df['Symbol'] == sym),
                      'Market'] = ticker[sym]['last']
    #print(signal_df[colSelect])

    #Portfolio File Checking
    if not os.path.exists(mornitorFilePath):
        port_df = pd.DataFrame(columns=colSelect)
        port_df.to_csv(mornitorFilePath, index=False)

    #Read User Portfolio
    port_df = pd.read_csv(mornitorFilePath)
    port_df = port_df[(port_df['User'] == idName)]
    port_df.reset_index(inplace=True)
    print('Portfolio')
    print(port_df['Symbol'].tolist())

    print('---------------------\nBuying\n---------------------')
    #Find New Buy
    buy_df = None
    if triggerBuyPos == 'Lower':
        buy_df = signal_df[(signal_df['Signal'] == triggerBuy) & (
            signal_df['Market'] < signal_df['BreakOut_ML'])][colSelect]
    elif triggerBuyPos == 'Upper':
        buy_df = signal_df[(signal_df['Signal'] == triggerBuy) & (
            signal_df['Market'] > signal_df['BreakOut_MH'])][colSelect]
    elif triggerBuyPos == 'Middle':
        buy_df = signal_df[(signal_df['Signal'] == triggerBuy) & (
            signal_df['Market'] < signal_df['BreakOut_M'])][colSelect]

    buy_df = buy_df.head(portSize)
    #print('Buy Data Frame')
    #print(buy_df[['Symbol','Signal','Market','BreakOut_MH','BreakOut_ML']])

    #Buy Condition
    for i in buy_df.index.tolist():
        row = buy_df.loc[i]
        text = '[ Buy ] {}\n{} Bath'.format(row['Symbol'], row['Buy'])
        #print('Buying {} : {}'.format(row['Symbol'],row['Market']))
        if row['Symbol'] in port_df['Symbol'].tolist(
        ):  #Symbol is in portfolio already
            #print('  Checking buy count')
            symbol_index = port_df[port_df['Symbol'] ==
                                   row['Symbol']].index.tolist()[0]
            if port_df.loc[symbol_index,
                           'Count'] < buySize:  #Buy position size is not full
                if row['Rec_Date'] != port_df.loc[
                        symbol_index, 'Rec_Date']:  #if Date Time not exist
                    # Do Buy
                    print('Buy {} more'.format(row['Symbol']))
                    portfolioList = port_df['Symbol'].tolist()
                    countLeft = (buySize * portSize) - (port_df['Count'].sum())
                    CreateBuyOrder(idName, row['Symbol'], portfolioList,
                                   countLeft)
                    Transaction(
                        idName, 'Buy', row['Symbol'],
                        (configJson[idName]['percentageComission'] / 100) * -1)
                    if sendNotify:
                        lineNotify.sendNotifyMassage(token, text)
                    port_df.loc[symbol_index, 'Count'] += 1
                    port_df.loc[symbol_index, 'Rec_Date'] = row['Rec_Date']
                    port_df.loc[symbol_index, 'Buy'] = round(
                        (port_df.loc[symbol_index, 'Buy'] + row['Buy']) * 0.5,
                        2)

        elif not row['Symbol'] in port_df['Symbol'].tolist(
        ):  #Symbol isn't in portfolio
            #print('  Checking port is not full')
            if port_df['Symbol'].count() < portSize:  #Portfolio isn't full
                # Do Buy
                print('Buy {} as new symbol'.format(row['Symbol']))
                portfolioList = port_df['Symbol'].tolist()
                countLeft = (buySize * portSize) - (port_df['Count'].sum())
                CreateBuyOrder(idName, row['Symbol'], portfolioList, countLeft)
                Transaction(idName, 'Buy', row['Symbol'],
                            (configJson[idName]['percentageComission'] / 100) *
                            -1)
                if sendNotify:
                    quote = row['Symbol'].split('_')[-1]
                    imgFilePath = imgPath + os.sep + '{}_{}.png'.format(
                        preset, quote)
                    lineNotify.sendNotifyImageMsg(token, imgFilePath, text)
                port_df = port_df.append(row, ignore_index=False)

    print('---------------------\nProfit Calulating\n---------------------')
    #Market Update and Calculate Profit
    for i in signal_df.index.tolist():
        row = signal_df.loc[i]
        if row['Symbol'] in port_df['Symbol'].tolist():
            print('Profit Update {}'.format(row['Symbol']))
            symbol_index = port_df[port_df['Symbol'] ==
                                   row['Symbol']].index.tolist()[0]
            port_df.loc[symbol_index, 'Market'] = row['Market']
            port_df.loc[symbol_index,
                        'Profit%'] = ((port_df.loc[symbol_index, 'Market'] -
                                       port_df.loc[symbol_index, 'Buy']) /
                                      port_df.loc[symbol_index, 'Buy']) * 100
            port_df.loc[symbol_index, 'Profit%'] = round(
                port_df.loc[symbol_index, 'Profit%'], 2)
            if (port_df.loc[symbol_index, 'Profit%'] <
                    0) and (abs(port_df.loc[symbol_index, 'Profit%']) >
                            port_df.loc[symbol_index, 'Max_Drawdown%']):
                port_df.loc[symbol_index,
                            'Max_Drawdown%'] = abs(port_df.loc[symbol_index,
                                                               'Profit%'])
            port_df.loc[symbol_index, 'Change4HR%'] = row['Change4HR%']
            port_df.loc[symbol_index, 'Volume'] = row['Volume']
            port_df.loc[symbol_index, 'BreakOut_H'] = row['BreakOut_H']
            port_df.loc[symbol_index, 'BreakOut_MH'] = row['BreakOut_MH']
            port_df.loc[symbol_index, 'BreakOut_M'] = row['BreakOut_M']
            port_df.loc[symbol_index, 'BreakOut_ML'] = row['BreakOut_ML']
            port_df.loc[symbol_index, 'BreakOut_L'] = row['BreakOut_L']
            port_df.loc[symbol_index, 'Low'] = row['Low']
            port_df.loc[symbol_index, 'High'] = row['High']
            port_df.loc[symbol_index, 'Signal'] = row['Signal']

    # Portfolio report
    if port_df['Symbol'].count(
    ) != 0 and reportHourDuration >= configJson[idName]['reportEveryHour']:
        gSheet.setValue('Config',
                        findKey='idName',
                        findValue=idName,
                        key='lastReport',
                        value=time.time())
        text = '[ Report ]\n' + \
               '{}\n'.format(' , '.join(port_df['Symbol'].tolist())) + \
               'Avg Profit {}%'.format(port_df['Profit%'].mean().round(2))
        print(text)
        if sendNotify:
            lineNotify.sendNotifyMassage(token, text)

    print('---------------------\nSelling\n---------------------')
    #Sell Condition
    for i in port_df.index.tolist():
        row = port_df.loc[i]
        sell_signal = False
        sell_profit = row['Profit%'] > profitTarget
        sell_loss = row['Profit%'] < lossTarget

        #Adaptive Loss
        if adaptiveLoss and sell_loss:
            gSheet.setValue('Config',
                            findKey='idName',
                            findValue=idName,
                            key='percentageLossTarget',
                            value=abs(row['Profit%']))

        if triggerSellPos == 'Lower':
            sell_signal = ((row['Signal'] == triggerSell)
                           and (row['Market'] < row['BreakOut_ML'])
                           and (row['Profit%'] > 1))
        elif triggerSellPos == 'Upper':
            sell_signal = ((row['Signal'] == triggerSell)
                           and (row['Market'] > row['BreakOut_MH'])
                           and (row['Profit%'] > 1))
        elif triggerSellPos == 'Middle':
            sell_signal = ((row['Signal'] == triggerSell)
                           and (row['Market'] > row['BreakOut_M'])
                           and (row['Profit%'] > 1))

        if sell_signal or sell_profit or sell_loss or isReset:  #Sell
            if isReset:
                port_df.loc[i, 'Count'] = 0  # Sell All
            else:
                port_df.loc[i, 'Count'] -= 1

            text = '[ Sell ] {}\n{} Bath ({}%)'.format(row['Symbol'],
                                                       row['Market'],
                                                       row['Profit%'])
            print(text)

            # Do Sell
            count = port_df.loc[i, 'Count'] + 1
            CreateSellOrder(idName, row['Symbol'], count=count)
            time.sleep(1)
            profit = ((row['Profit%'] / buySize) *
                      row['Count']) / portSize  #real percentage of total cost
            Transaction(
                idName, 'Sell', row['Symbol'],
                ((configJson[idName]['percentageComission'] / 100) * -1) +
                profit)
            if sendNotify:
                lineNotify.sendNotifyMassage(token, text)

        if port_df.loc[i, 'Count'] <= 0:  #Delete symbol if no count
            port_df = port_df[port_df['Symbol'] != row['Symbol']]

    #Finish
    if 'index' in port_df.columns.tolist():
        port_df.drop(columns=['index'], inplace=True)
    alluser_df = pd.read_csv(mornitorFilePath)
    alluser_df = alluser_df[alluser_df['User'] != idName]
    alluser_df = alluser_df.append(port_df)
    alluser_df.to_csv(mornitorFilePath, index=False)
    print('---------------------\nFinish\n---------------------\n')
Exemple #4
0
def Reset(*_):
    print('---------------------\nReset\n---------------------')
    global mornitorFilePath
    global transacFilePath
    if not os.path.exists(mornitorFilePath):
        return None
    m_df = pd.read_csv(mornitorFilePath)
    t_df = pd.read_csv(transacFilePath)
    deleteList = []

    m_user_list = m_df['User'].unique().tolist()
    t_user_list = t_df['User'].unique().tolist()
    for user in m_user_list:
        print('Checking User {} in Mornitor'.format(user))
        if not user in list(configJson):
            deleteList.append(user)
    for user in t_user_list:
        print('Checking User {} in Transaction'.format(user))
        if not user in list(configJson):
            deleteList.append(user)

    #Sending Restart
    for user in list(configJson):
        if bool(configJson[user]['reset']):
            text = '[ Reset Portfoilo ]\n' +\
                   'User ID : {} \n'.format(user) +\
                   'Preset ID : {} \n'.format(configJson[user]['preset']) +\
                   'System ID : {} \n'.format(configJson[user]['system']) +\
                   'Portfolio Size : {} \n'.format(configJson[user]['portSize']) +\
                   'Position Size : {} \n'.format(configJson[user]['buySize']) +\
                   'Target Profit : {}%'.format(configJson[user]['percentageProfitTarget'])
            lineNotify.sendNotifyMassage(configJson[user]['lineToken'], text)
            gSheet.setValue('Config',
                            findKey='idName',
                            findValue=user,
                            key='reset',
                            value=0)
            gSheet.setValue('Config',
                            findKey='idName',
                            findValue=user,
                            key='lastReport',
                            value=time.time())
            print(text)

            #Clear all real portfolio
            API_KEY = configJson[user]['bk_apiKey']
            API_SECRET = configJson[user]['bk_apiSecret']
            bitkub = Bitkub()
            bitkub.set_api_key(API_KEY)
            bitkub.set_api_secret(API_SECRET)
            balance = getBalance(user)
            #print(balance)
            for sym in balance:
                if sym == 'THB':
                    continue
                symbol = 'THB_{}'.format(sym)
                print(symbol)
                print('Sell {} {}'.format(balance[sym]['available'], sym))
                CreateSellOrder(user, symbol, count=1)

    for user in deleteList:
        print('delete [ {} ]'.format(user))
        m_df = m_df[m_df['User'] != user]
        t_df = t_df[t_df['User'] != user]

    m_df.to_csv(mornitorFilePath, index=False)
    t_df.to_csv(transacFilePath, index=False)
    print('User Reset')
Exemple #5
0
def MornitoringUser(idName, sendNotify=True):
    isActive = bool(configJson[idName]['active'])
    isReset = bool(configJson[idName]['reset'])
    if isActive == False:
        return None
    print('---------------------\n[ {} ]  Monitoring\n---------------------'.
          format(idName))
    ticker = kbApi.getTicker()
    now = round(time.time())
    reportHourDuration = round(
        float(((now - configJson[idName]['lastReport']) / 60) / 60), 2)
    preset = configJson[idName]['preset']
    system = configJson[idName]['system']
    token = configJson[idName]['lineToken']
    size = int(systemJson[system]['size'])
    profitTarget = float(systemJson[system]['percentageProfitTarget'])
    duplicateBuyCount = 2
    secondaryBuy = bool(systemJson[system]['secondaryBuy'])
    print('Last Report  {} Hour Ago / Report Every {} H'.format(
        reportHourDuration, configJson[idName]['reportEveryHour']))

    signal_df = pd.read_csv(dataPath + '/signal.csv')
    signal_df = signal_df[
        (signal_df['Rec_Date'] == signal_df['Rec_Date'].max())
        & (signal_df['Preset'] == preset)]
    signal_df.reset_index(inplace=True)

    # New Column For Signal DF
    signal_df['User'] = idName
    signal_df['Buy'] = signal_df['Close']
    signal_df['Market'] = signal_df['Close']
    signal_df['Profit%'] = (
        (signal_df['Market'] - signal_df['Buy']) / signal_df['Buy']) * 100
    signal_df['Max_Drawdown%'] = 0.0
    signal_df['Buy_Count'] = 0
    for sym in ticker:
        signal_df.loc[(signal_df['Symbol'] == sym),
                      'Buy'] = ticker[sym]['last']

    # Select Entry
    entry_df = signal_df
    #entry_df['Change4HR%_Abs'] = entry_df['Change4HR%'].abs()
    entry_df = entry_df[
        (entry_df['Rec_Date'] == entry_df['Rec_Date'].max()) &
        (entry_df['Signal'] == 'Entry') & (entry_df['Preset'] == preset)
        #( entry_df['Change4HR%'] >= 0 ) &
        #( entry_df['Close'] <= entry_df['BreakOut_M'] )
    ]
    #entry_df = entry_df.sort_values(['Change4HR%_Abs','Value_M'], ascending=[True,False])
    entry_df = entry_df.sort_values(['Change4HR%', 'Value_M'],
                                    ascending=[True, False])
    #entry_df = entry_df.head(size) # Select Count
    entry_df.reset_index(inplace=True)
    #print(entry_df) # Signal Checking
    """
    # New Column For Entry DF
    entry_df['User'] = idName
    entry_df['Buy'] = entry_df['Close']
    entry_df['Market'] = entry_df['Close']
    entry_df['Profit%'] = ( ( entry_df['Market'] - entry_df['Buy'] ) / entry_df['Buy'] ) * 100
    entry_df['Max_Drawdown%'] =  0.0
    """

    colSelect = [
        'User', 'Symbol', 'Signal', 'Buy', 'Market', 'Profit%',
        'Max_Drawdown%', 'Change4HR%', 'Value_M', 'BreakOut_H', 'BreakOut_MH',
        'BreakOut_M', 'BreakOut_ML', 'BreakOut_L', 'Low', 'High', 'Rec_Date',
        'Buy_Count'
    ]
    entry_df = entry_df[colSelect]
    #print(entry_df[['Symbol','Signal','Change4HR%']])
    print('Select Entry {}'.format(entry_df['Symbol'].to_list()))

    # Mornitor data frame
    global mornitorFilePath
    if not os.path.exists(mornitorFilePath):
        morn_df = pd.DataFrame(columns=colSelect)
        morn_df.to_csv(mornitorFilePath, index=False)
    morn_df = pd.read_csv(mornitorFilePath)

    # Checking Column
    for c in colSelect:
        if not c in morn_df.columns.tolist():
            morn_df[c] = None

    #Portfolio
    portfolioList = morn_df[morn_df['User'] == idName]['Symbol'].tolist()
    portfolioCount = morn_df[morn_df['User'] == idName]['Buy_Count'].sum()
    print('{} Portfolio have {}'.format(idName, portfolioList))

    # Buy Notify (by Singnal)
    # ==============================
    for i in range(entry_df['Symbol'].count()):
        if isReset:
            break
        row = entry_df.iloc[i]
        buy_condition = ((not row['Symbol'] in portfolioList)
                         and (portfolioCount < size) and  # Port is not full
                         (row['BreakOut_ML'] != row['BreakOut_L']) and
                         (row['BreakOut_MH'] != row['BreakOut_H']) and
                         (row['Low'] != row['BreakOut_ML']) and
                         (row['Low'] < row['BreakOut_M']))

        if buy_condition and not row['Symbol'] in portfolioList:  # Buy Primary
            row['Buy_Count'] = 1
            text = '[ Buy ] {}\n{} Bath'.format(row['Symbol'], row['Buy'])
            quote = row['Symbol'].split('_')[-1]

            #entry_df['Buy_Count'].iloc[i] = row['Buy_Count']+1
            imgFilePath = imgPath + os.sep + '{}_{}.png'.format(preset, quote)
            print(text)
            print(imgFilePath)
            if sendNotify:
                lineNotify.sendNotifyImageMsg(token, imgFilePath, text)
            morn_df = morn_df.append(row, ignore_index=True)
            morn_df['Buy'] = morn_df.groupby(['User', 'Symbol'
                                              ]).transform('first')['Buy']

            portfolioList.append(row['Symbol'])
            portfolioCount += 1

            CreateBuyOrder(idName, row['Symbol'], portfolioList)
            Transaction(idName, 'Buy', row['Symbol'],
                        (systemJson[system]['percentageComission'] / 100) * -1)
        elif portfolioCount >= size or row[
                'Symbol'] in portfolioList:  # Port is Full or Duplicate Buy is Limited
            print('Can\'t Buy More Because Size is Full...')
            break
    # ==============================

    # Update Checking
    for i in range(signal_df['Symbol'].count()):
        if isReset:
            break
        row = signal_df.iloc[i]
        port_df = morn_df[(morn_df['User'] == idName)
                          & (morn_df['Symbol'] == row['Symbol'])]
        if port_df['Symbol'].count() != 0:  #Have Symbol in Port
            buy_low_condition = (
                secondaryBuy and (row['Symbol'] in portfolioList)
                and  #is already in port
                (portfolioCount < size) and  # size is not full
                (row['BreakOut_ML'] != row['BreakOut_L'])
                and (row['BreakOut_ML'] < row['BreakOut_M'])
                and (row['Market'] < row['BreakOut_ML'])
                and (port_df['Buy_Count'].tolist()[0] >= 1)
                and (port_df['Buy_Count'].tolist()[0] < 2))
            if buy_low_condition:  # Secondary Buying
                row['Buy_Count'] = 1
                text = '[ Secondary Buy ] {}\n{} Bath\nStop Loss {} Bath'.format(
                    row['Symbol'], row['Market'], row['BreakOut_L'])
                if sendNotify:
                    lineNotify.sendNotifyMassage(token, text)
                morn_df = morn_df.append(row, ignore_index=True)
                morn_df['Buy'] = morn_df.groupby(['User', 'Symbol'
                                                  ]).transform('mean')['Buy']
                CreateBuyOrder(idName, row['Symbol'], portfolioList)
                Transaction(idName, 'Buy', row['Symbol'],
                            (systemJson[system]['percentageComission'] / 100) *
                            -1)
            # Update Trailing
            trailing_condition = (
                (row['Symbol'] in portfolioList)
                and (ticker[row['Symbol']]['last'] > row['BreakOut_M']))
            if trailing_condition:
                morn_df = morn_df.append(row, ignore_index=True)
                print('Updated Trailing ( {} )'.format(row['Symbol']))
    # ==============================

    morn_df = morn_df[colSelect]

    # Ticker ( Update Last Price as 'Market' )
    for sym in ticker:
        if not sym in morn_df['Symbol'].unique().tolist():
            continue
        morn_df.loc[morn_df['Symbol'] == sym, 'Market'] = ticker[sym]['last']
    print('Update Market Price')

    # Calculate in Column
    print('Profit Calculating...')
    if not morn_df.empty:
        morn_df['Buy_Count'] = morn_df.groupby(
            ['User', 'Symbol']).transform('sum')['Buy_Count']
        morn_df['Buy'] = morn_df.groupby(['User',
                                          'Symbol']).transform('first')['Buy']
        morn_df['Profit%'] = (
            (morn_df['Market'] - morn_df['Buy']) / morn_df['Buy']) * 100
        morn_df['Profit%'] = morn_df['Profit%'].round(2)
        morn_df.loc[(morn_df['Profit%'] < 0.0) &
                    (morn_df['Max_Drawdown%'] == 0.0),
                    'Max_Drawdown%'] = morn_df['Profit%'].abs()
        morn_df.loc[(morn_df['Profit%'] > 0.0) &
                    (morn_df['Max_Drawdown%'] == 0.0), 'Max_Drawdown%'] = 0.0
        morn_df.loc[(morn_df['Profit%'] < 0.0) &
                    (morn_df['Profit%'] < morn_df['Max_Drawdown%'].abs() * -1),
                    'Max_Drawdown%'] = morn_df['Profit%'].abs()
        morn_df['Max_Drawdown%'] = morn_df.groupby(
            ['User', 'Symbol'])['Max_Drawdown%'].transform('max')
        morn_df.drop_duplicates(['User', 'Symbol'], keep='last', inplace=True)
        morn_df.to_csv(mornitorFilePath, index=False)

    # Reload mornitor again
    morn_df = pd.read_csv(mornitorFilePath)
    morn_df = morn_df.sort_values(['User', 'Profit%'], ascending=[True, False])
    holdList = morn_df[(morn_df['User'] == idName) & (
        morn_df['Profit%'] > 0.0)].head(size)['Symbol'].tolist()

    # Sell Notify
    # ==============================
    """
    sell_df = signal_df[
        (signal_df['Signal'] == 'Exit') &
        (signal_df['Preset'] == preset)
        ]
    """
    sellList = []
    for i in range(morn_df['Symbol'].count()):
        row = morn_df.iloc[i]
        text = '[ Sell ] {}\n{} Bath ({}%)'.format(row['Symbol'],
                                                   row['Market'],
                                                   row['Profit%'])
        sell_condition = (  # Sell Default
            (row['Market'] < row['BreakOut_L']) and
            (row['User'] == idName)) or ((row['User'] == idName) and
                                         (row['Profit%'] > profitTarget))
        if (row['Profit%'] <= 0.0):  # Fast Cut Loss if no profit
            sell_condition = (  # Sell Default
                (row['Market'] < row['BreakOut_ML'])
                and (row['User'] == idName))
        if sell_condition:
            print(text)
            if sendNotify:
                lineNotify.sendNotifyMassage(token, text)
            sellList.append({'User': row['User'], 'Symbol': row['Symbol']})
    # ==============================

    #Report
    report_df = morn_df[morn_df['User'] == idName]
    report_df = report_df.sort_values(['Profit%'], ascending=[False])

    #Portfolio report
    if report_df['Symbol'].count(
    ) != 0 and reportHourDuration >= configJson[idName]['reportEveryHour']:
        gSheet.setValue('Config',
                        findKey='idName',
                        findValue=idName,
                        key='lastReport',
                        value=time.time())
        text = '[ Report ]\n' +\
                '{}\n'.format( ' , '.join(report_df['Symbol'].tolist()) ) +\
                'Profit Sum {}%\n'.format(report_df['Profit%'].sum().round(2)) + \
               'Profit Average {}%'.format(report_df['Profit%'].mean().round(2))
        print(text)
        if sendNotify:
            lineNotify.sendNotifyMassage(token, text)

    #Take profit all (Clear Portfolio)
    profit_condition = ((report_df['Profit%'].mean() >= profitTarget)
                        and (report_df['Profit%'].count() >= size))
    if (profit_condition or isReset) and report_df['Profit%'].count() != 0:
        gSheet.setValue('Config',
                        findKey='idName',
                        findValue=idName,
                        key='reset',
                        value=1)
        text = '[ Take Profit ]\n' + \
               'Target Profit {}%\n'.format(profitTarget) + \
               'Profit Average {}%'.format(report_df['Profit%'].mean().round(2))
        print(text)
        if sendNotify:
            lineNotify.sendNotifyMassage(token, text)

        # Prepare Sell When Take Profit or Reset
        for sym in report_df['Symbol'].tolist():
            if sym in sellList:
                continue
            sellList.append({'User': idName, 'Symbol': sym})

    # Sell And Delete Symbol
    for i in sellList:
        profit = morn_df[(morn_df['User'] == i['User']) & (
            morn_df['Symbol'] == i['Symbol'])]['Profit%'].tolist()[0]
        profit = profit / size
        morn_df = morn_df.drop(
            morn_df[(morn_df['User'] == i['User'])
                    & (morn_df['Symbol'] == i['Symbol'])].index)
        CreateSellOrder(i['User'], i['Symbol'])
        Transaction(i['User'], 'Sell', i['Symbol'],
                    ((systemJson[system]['percentageComission'] / 100) * -1) +
                    profit)

    #Finish
    morn_df.to_csv(mornitorFilePath, index=False)
    print('{} Update Finished\n'.format(idName))