# cd /www/server/mdserver-web &&  source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_macd_trade.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_macd_trade.py long


import ccxt
import talib

import sys
import os
import time
import json
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np

sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common

sys.path.append(os.getcwd() + "/class/core")
import mw

exchange = common.initEx()
exchange.load_markets()

# 默认开仓数据
# default_open_num = 10

default_open = {
    'ETH/USDT': 30,
    'DOT/USDT': 30,
    'CEL/USDT': 30,
}

default_sell = {
    'ETH/USDT': 0.02,
    'DOT/USDT': 5,
    'CEL/USDT': 85,
}


# 做多开仓
def onBuyOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):

    # 信号只在一个周期内执行一次|start
    lock_file = common.getServerDir() + '/signal.json'
    if not os.path.exists(lock_file):
        mw.writeFile(lock_file, '{}')

    stype = symbol.replace('/', '_') + '_' + timeframe
    trigger_time = common.toUnixTimeSecond(timeframe)
    lock_data = json.loads(mw.readFile(lock_file))
    if stype in lock_data:
        diff_time = time.time() - lock_data[stype]['do_time']
        if diff_time >= trigger_time:
            lock_data[stype]['do_time'] = time.time()
        else:
            return False, 0, 0
    else:
        lock_data[stype] = {'do_time': time.time()}

    mw.writeFile(lock_file, json.dumps(lock_data))
    # 信号只在一个周期内执行一次|end

    common.writeLogEx('------做多----------------------------------', symbol)

    default_open_num = default_open[symbol]
    # 做多开仓 | 市价
    data = exchange.createMarketBuyOrder(
        symbol, default_open_num, {"tdMode": "cross"})

    common.writeLogEx('开仓数据:', symbol)
    common.writeLogEx(json.dumps(data), symbol)

    order_id = data['info']['ordId']
    order_data = exchange.fetchOrder(order_id, symbol)

    common.writeLogEx('订单数据:', symbol)
    common.writeLogEx(json.dumps(order_data), symbol)

    # 实际开场平均价
    open_price = order_data['info']['avgPx']

    # 做多-止损价大于开仓价,重设止损价
    if float(stop_loss_price) <= float(open_price):
        stop_loss_price = float(open_price) * float((1 - 0.003))

    # property_val = float(order_data['info']['accFillSz']) + float(order_data['info']['fee'])
    property_val = common.addition(
        order_data['info']['accFillSz'], order_data['info']['fee'])
    property_val = float(property_val)

    # 可平仓的数量
    property_val = common.roundValCeil(
        property_val, order_data['info']['accFillSz'])

    common.writeLogEx('可平仓资产:' + str(property_val), symbol)

    # 止盈价
    diff = float(open_price) - float(stop_loss_price)
    closing_price_c = float(open_price) + (diff * 2)
    closing_price = float(open_price) * float((1 + profit))
    # 选择盈利多的
    if closing_price_c > closing_price:
        closing_price = closing_price_c

    closing_price = common.roundVal(closing_price, stop_loss_price)
    # stop_loss_price = common.roundVal(stop_loss_price, open_price)
    common.writeLogEx('实际开仓价:' + str(open_price), symbol)
    common.writeLogEx('止盈价:' + str(closing_price), symbol)
    common.writeLogEx('止损价:' + str(stop_loss_price), symbol)

    # 设置 - 止损价/止盈价
    sl_exchange_params = {
        'ccy': "USDT",
        'reduceOnly': True,
        'tdMode': "cross",
        'slOrdPx': "-1",
        'slTriggerPx': stop_loss_price,
    }

    # 止损条件单
    common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'sell',
                                            property_val, stop_loss_price, sl_exchange_params]), symbol)
    sl_cond_data = exchange.create_order(
        symbol, 'limit', 'sell', property_val, stop_loss_price, sl_exchange_params)

    common.writeLogEx('止损价数据:', symbol)
    common.writeLogEx(json.dumps(sl_cond_data), symbol)

    # 止赢条件单
    tp_exchange_params = {
        'ccy': "USDT",
        'reduceOnly': True,
        'tdMode': "cross",
        'tpOrdPx': "-1",
        'tpTriggerPx': closing_price,
    }

    common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'sell',
                                            property_val, closing_price, tp_exchange_params]), symbol)
    tp_cond_data = exchange.create_order(
        symbol, 'limit', 'sell', property_val, closing_price, tp_exchange_params)

    common.writeLogEx('止赢数据:', symbol)
    common.writeLogEx(json.dumps(tp_cond_data), symbol)

    common.writeLogEx('------做多 end----------------------------------', symbol)
    return True, open_price, closing_price


def onBuyOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
    # 做多开仓
    # profit 百分比
    try:
        return onBuyOrderTry(symbol, stop_loss_price, profit, timeframe)
    except Exception as e:
        common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
        return False, 0, 0


def onSellOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):

    # 信号只在一个周期内执行一次|start
    lock_file = common.getServerDir() + '/signal.json'
    if not os.path.exists(lock_file):
        mw.writeFile(lock_file, '{}')

    stype = symbol.replace('/', '_') + '_' + timeframe
    trigger_time = common.toUnixTimeSecond(timeframe)
    lock_data = json.loads(mw.readFile(lock_file))
    if stype in lock_data:
        diff_time = time.time() - lock_data[stype]['do_time']
        if diff_time >= trigger_time:
            lock_data[stype]['do_time'] = time.time()
        else:
            return False, 0, 0
    else:
        lock_data[stype] = {'do_time': time.time()}

    mw.writeFile(lock_file, json.dumps(lock_data))
    # 信号只在一个周期内执行一次|end
    common.writeLogEx('------做空----------------------------------', symbol)

    # 计算借币卖币多多少,以USDT为基准
    # sell_num = float(default_open_num) / float(stop_loss_price)
    # sell_num = round(sell_num, 8)

    sell_num = default_sell[symbol]
    # 做空开仓 | 市价
    data = exchange.createMarketSellOrder(
        symbol, sell_num, {"tdMode": "cross", 'ccy': "USDT"})

    common.writeLogEx('开仓数据:', symbol)
    common.writeLogEx(json.dumps(data), symbol)

    order_id = data['info']['ordId']
    order_data = exchange.fetchOrder(order_id, symbol)

    common.writeLogEx('订单数据:', symbol)
    common.writeLogEx(json.dumps(order_data), symbol)

    # 实际开场平均价
    open_price = order_data['info']['avgPx']

    common.writeLogEx('可平仓资产:' + str(sell_num), symbol)

    # 做空-止损价小于开仓价,重设止损价
    if float(stop_loss_price) <= float(open_price):
        stop_loss_price = float(open_price) * float((1 + 0.003))

    # 止盈价
    diff = float(stop_loss_price) - float(open_price)
    closing_price_c = float(open_price) - (diff * 2)
    closing_price = float(open_price) * float((1 - profit))
    # 选择盈利多的
    if closing_price_c < closing_price:
        closing_price = closing_price_c

    closing_price = common.roundVal(closing_price, open_price)
    stop_loss_price = common.roundVal(stop_loss_price, open_price)
    common.writeLogEx('实际开仓价:' + str(open_price), symbol)
    common.writeLogEx('止盈价:' + str(closing_price), symbol)
    common.writeLogEx('止损价:' + str(stop_loss_price), symbol)

    # 设置 - 止损价
    sl_exchange_params = {
        'ccy': "USDT",
        'reduceOnly': True,
        'tdMode': "cross",
        'slOrdPx': "-1",
        'slTriggerPx': stop_loss_price,
    }

    sl_amount = common.multiply(stop_loss_price, sell_num)
    # 解决平仓时,未全部平仓
    sl_amount = common.addition(sl_amount, 0.1)
    common.writeLogEx('止损总价值:' + str(sl_amount), symbol)
    common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'buy', float(
        sl_amount), stop_loss_price, sl_exchange_params]), symbol)
    sl_cond_data = exchange.create_order(
        symbol, 'limit', 'buy', sl_amount, stop_loss_price, sl_exchange_params)

    common.writeLogEx('止损价数据:', symbol)
    common.writeLogEx(json.dumps(sl_cond_data), symbol)

    tp_exchange_params = {
        'ccy': "USDT",
        'reduceOnly': True,
        'tdMode': "cross",
        'tpOrdPx': "-1",
        'tpTriggerPx': closing_price,
    }

    # 设置 -止盈价
    tp_amount = common.multiply(closing_price, sell_num)
    # 解决平仓时,未全部平仓
    tp_amount = common.addition(tp_amount, 0.1)
    common.writeLogEx('止盈总价值:' + str(tp_amount), symbol)
    common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'buy', float(
        tp_amount), closing_price, tp_exchange_params]), symbol)
    tp_cond_data = exchange.create_order(
        symbol, 'limit', 'buy', tp_amount, closing_price, tp_exchange_params)

    common.writeLogEx('止盈价数据:', symbol)
    common.writeLogEx(json.dumps(tp_cond_data), symbol)

    common.writeLogEx('------做空 end----------------------------------', symbol)
    return True, open_price, closing_price


def onSellOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
    # 做空开仓
    # profit 百分比
    try:
        return onSellOrderTry(symbol, stop_loss_price, profit, timeframe)
    except Exception as e:
        common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
        return False, 0, 0


def getOnlineData(symbol,  input_tf="15m", limit=230):
    bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=limit)
    df = pd.DataFrame(bars[:], columns=['timestamp',
                                        'open', 'high', 'low', 'close', 'volume'])
    df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
    df.set_index('dt', inplace=True)
    df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
    return df


def isKdj(last, last_pre):
    # 判断是否是金叉
    if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
        return True
    return False


def isDeadFork(last, last_pre):
    # 判断是否是死叉
    if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
        return True
    return False


def getMACD(df, lenght=-60):
    if len(df['close'].values) < 100:
        return False, None

    close_p = df['close'].values
    df['dif'], df['dea'], df['macd'] = talib.MACD(close_p,
                                                  fastperiod=12,
                                                  slowperiod=26,
                                                  signalperiod=9)
    return df[lenght:]


def getEMA(df):
    close_p = df['close'].values
    df['ema'] = talib.EMA(np.array(close_p), timeperiod=200)
    return df


def doneMacd(data, tag, timeframe):
    data = getEMA(data)

    ma_data = getMACD(data)
    # alen = len(data)
    # print(ma_data)

    t_data = ma_data.tail(3)
    # print(t_data)

    last_pre = t_data.iloc[0]
    last = t_data.iloc[1]

    # print(last)
    # print(last.index)

    # print('close:', last['close'], 'ema:', last['ema'])

    obj = common.MsgTpl()
    symbol = tag.upper() + '/USDT'
    obj.setName(symbol)
    obj.setStrategyName("MACD检查")
    obj.setTimeFrame(timeframe)
    obj.setOpenTime(last['timestamp'] / 1000)

    now_data = t_data.iloc[2]
    # print('now_data:', now_data)

    # msg = obj.toText()
    # print(msg)

    if isKdj(last, last_pre) and last['close'] > last['ema']:
        # if isKdj(last, last_pre):

        # closing_price = common.calc_ClosingPrice(
        #     now_data['close'], last_pre['low'], 'buy')
        # # print('closing_price:', closing_price)

        # 做多止损点
        stop_loss_price = last_pre['low']
        buy_status, open_price, closing_price = onBuyOrder(
            symbol, stop_loss_price, 0.005, timeframe)

        if buy_status:
            obj.setStrategicDt('buy')
            # 做多止损点
            obj.setStopLossPrice(str(stop_loss_price))
            obj.setOpenPrice(str(open_price))
            obj.setClosingPrice(str(closing_price))
            obj.setContent("检查到金叉状态")
            msg = obj.toText()
            print(msg)
            common.notifyMsg(msg, timeframe, tag)
            common.writeLog(msg)

    if isDeadFork(last, last_pre) and last['close'] < last['ema']:
        # if isDeadFork(last, last_pre):
        # closing_price = common.calc_ClosingPrice(
        #     now_data['close'], last_pre['high'], 'sell')

        # 做空止损点
        stop_loss_price = last_pre['high']
        sell_status, open_price, closing_price = onSellOrder(
            symbol, stop_loss_price, 0.005, timeframe)
        if sell_status:
            obj.setStopLossPrice(str(stop_loss_price))
            obj.setOpenPrice(str(open_price))
            obj.setClosingPrice(str(closing_price))
            obj.setStrategicDt('sell')
            obj.setContent("检查到死叉状态")
            msg = obj.toText()
            print(msg)
            common.notifyMsg(msg, timeframe, tag)
            common.writeLog(msg)


def mainProcess(tag, timeframe='15m'):
    symbol = tag.upper() + '/USDT'
    data = getOnlineData(symbol, timeframe)

    doneMacd(data, tag, timeframe)


def foreachList():
    tag_list = [
        'eth', 'dot'
    ]

    for tag in tag_list:
        mainProcess(tag, '15m')
        time.sleep(1)


def longRun():
    while True:
        foreachList()
        time.sleep(3)


def debug():
    while True:
        mainProcess('xrp', '1m')
        time.sleep(3)


if __name__ == "__main__":
    func = sys.argv[1]
    if func == 'long':
        longRun()
    elif func == 'run':
        debug()
    else:
        print('error')
