TradingView信号- V 0.2.21


创建日期: 2025-01-27 22:41:39 最后修改: 2025-05-21 03:44:44
复制: 0 点击次数: 235
avatar of 豆豆 豆豆
22
关注
17
关注者

从TV的闹钟里发送的消息内容为: OpenLong 开多 OpenShort 开空 CloseLong 平多 CloseShort 平空

警报名称随便填写,消息内容就是上面的英文(只填英文,不要带空格和其他符号) 记得填写正确的Webhook URL

参考地址:https://www.fmz.com/bbs-topic/5533

说明:

从TV接收止损信号,但TV信号发送是在K棒结束之后,本脚本中的止损为防止插针设计; 止盈可以比TV的止盈大一些,大约0.25倍的样子(说的是小止盈0.75%那种)。

策略源码
// @ts-check

////TradingView信号
////从TradingView接收开仓、平仓信号(OpenLong/CloseLong,OpenShort/CloseShort)执行开仓、平仓操作。
////记得填写正确的Webhook URL   参考地址: https://www.fmz.com/bbs-topic/5533


// 参数设置

// 基本设置
var _trade_currency                         = null;                             // 交易对
var _interval                               = Interval;                         // 程序运行周期
var _use_quarter                            = UseQuarter;                       // 季度合约,默认USDT永续合约
var _enable_message_send                    = EnableMessageSend;                // 推送消息

// 下单设置
var _margin_level                           = MarginLevel;                      // 杠杆倍数
var _order_size                             = OrderSize;                        // 下单数量/张数
var _order_by_margin                        = OrderByMargin;                    // 根据下单保证金来确定下单数量
var _order_margin_percent                   = OrderMarginPercent;               // 下单保证金百分比%(根据初始资金计算)
var _price_precision                        = PricePrecision;                   // 下单价格精度
var _amount_precision                       = AmountPrecision;                  // 下单数量精度
var _one_size_in_current_coin               = OneSizeInCurrentCoin;             // U本位合约中,一张ETH所代表的ETH数量
var _quarter_one_size_value                 = QuarterOneSizeValue;              // 币本位合约中,一张ETH所代表的USDT数量


//// 止盈止损 ////
// 止损
var _STOPLOSS_PRICEPERCENT                  = StopLossPricePercent;             // 止损价格百分比

// 挂单止盈
var _TAKEPROFIT_ORDER_OPEN                  = TakeProfit_OrderOpen                      // 挂单止盈开关

var _TAKEPROFIT_ORDER_PRICEPERCENT_1        = TakeProfit_Order_PricePercent_1;          // 挂单止盈-1-价格百分比%
var _TAKEPROFIT_ORDER_AMOUNTPERCENT_1       = TakeProfit_Order_AmountPercent_1;         // 挂单止盈-1-数量百分比%

var _TAKEPROFIT_ORDER_PRICEPERCENT_2        = TakeProfit_Order_PricePercent_2;          // 挂单止盈-2-价格百分比%
var _TAKEPROFIT_ORDER_AMOUNTPERCENT_2       = TakeProfit_Order_AmountPercent_2;         // 挂单止盈-2-数量百分比%

var _TAKEPROFIT_ORDER_PRICEPERCENT_3        = TakeProfit_Order_PricePercent_3;          // 挂单止盈-2-价格百分比%
var _TAKEPROFIT_ORDER_AMOUNTPERCENT_3       = TakeProfit_Order_AmountPercent_3;         // 挂单止盈-2-数量百分比%

var _TAKEPROFIT_ORDER_PRICEPERCENT_4        = TakeProfit_Order_PricePercent_4;          // 挂单止盈-2-价格百分比%
var _TAKEPROFIT_ORDER_AMOUNTPERCENT_4       = TakeProfit_Order_AmountPercent_4;         // 挂单止盈-2-数量百分比%

var _TAKEPROFIT_ORDER_PRICEPERCENT_5        = TakeProfit_Order_PricePercent_5;          // 挂单止盈-2-价格百分比%
var _TAKEPROFIT_ORDER_AMOUNTPERCENT_5       = TakeProfit_Order_AmountPercent_5;         // 挂单止盈-2-数量百分比%


//// 回调止盈 ////

// 固定回调
var _PULLBACK_FIXED_OPEN                    = PullbackFixedOpen;      // 机制--是否启用固定回调止盈?
var _PULLBACK_FIXED_STARTPRICEPERCENT       = PullbackFixedStartPricePercent;             // 盈利达到多少开启固定回调

var _PULLBACK_FIXED_PRICEPERCENT_1          = PullbackFixedPricePercent_1;          // 止盈回调点位1(回调百分比%),到达这个点位,减仓
var _PULLBACK_FIXED_AMOUNTPERCENT_1         = PullbackFixedAmountPercent_1;           // 回调止盈点位1 的数量百分比

var _PULLBACK_FIXED_PRICEPERCENT_2          = PullbackFixedPricePercent_2;          // 止盈回调点位2(回调百分比%),到达这个点位,减仓


// 利润回调
var _PULLBACK_PROFIT_OPEN                   = PullbackProfitOpen;                       // 机制--是否启用利润回调止盈?
var _PULLBACK_PROFIT_OPEN_2                 = PullbackProfitOpen_2;                     // 机制--是否启用利润回调平仓?

var _PULLBACK_PROFIT_STARTPRICEPERCENT      = PullbackProfitStartPricePercent;            // 利润达到百分之多少,开始利润回调

//var _PULLBACK_PROFIT_PRICEPERCENT         = PullbackProfitPricePercent;           // 利润回调百分之多少,则减仓
var _PULLBACK_PROFIT_AMOUNTPERCEHT          = PullbackProfitAmountPercent;            // 利润回调减仓数量(当前持有仓位的百分之多少)

var _PULLBACK_PROFIT_MAXREPEATTIMES         = PullbackProfitMaxRepeatTimes;       // 最多执行多少次利润回调止盈

var _PULLBACK_PROFIT_MULT_1                 = PullbackProfitMult_1;             // 利润回调止盈乘数
var _PULLBACK_PROFIT_MULT_2                 = PullbackProfitMult_2;             // 利润回调平仓乘数




////运算变量

var _positions_type                         = null;                             // 用于挂单止盈之后的收益展示
var _OpenPositionsTime                      = 0;                                // 开仓时候的时间戳,用于限制回调止盈的在开仓时候出问题

// 止损
var _stoploss_price                         = 0;                                // 止损价格,用于止损运算
var _had_stoploss                           = false;                            // 已经达到止损价格

// 挂单止盈
var _takeprofit_order_price_1               = 0;                                // 挂单止盈价格-1
var _takeprofit_order_amount_1              = 0;                                // 挂单止盈数量-1

var _takeprofit_order_price_2               = 0;                                // 挂单止盈价格-2
var _takeprofit_order_amount_2              = 0;                                // 挂单止盈数量-2

var _takeprofit_order_price_3               = 0;                                // 挂单止盈价格-3
var _takeprofit_order_amount_3              = 0;                                // 挂单止盈数量-3

var _takeprofit_order_price_4               = 0;                                // 挂单止盈价格-4
var _takeprofit_order_amount_4              = 0;                                // 挂单止盈数量-4

var _takeprofit_order_price_5               = 0;                                // 挂单止盈价格-5
var _takeprofit_order_amount_5              = 0;                                // 挂单止盈数量-5

var _takeprofit_order_id_1                  = null;                             // 记录止盈单ID
var _takeprofit_order_id_2                  = null;                             // 记录止盈单ID
var _takeprofit_order_id_3                  = null;                             // 记录止盈单ID
var _takeprofit_order_id_4                  = null;                             // 记录止盈单ID
var _takeprofit_order_id_5                  = null;                             // 记录止盈单ID

var _takeprofit_order_hastakeprofit_1       = false;                            // 是否止盈过?  用于打印收益信息
var _takeprofit_order_hastakeprofit_2       = false;                            // 是否止盈过?  用于打印收益信息
var _takeprofit_order_hastakeprofit_3       = false;                            // 是否止盈过?  用于打印收益信息
var _takeprofit_order_hastakeprofit_4       = false;                            // 是否止盈过?  用于打印收益信息
var _takeprofit_order_hastakeprofit_5       = false;                            // 是否止盈过?  用于打印收益信息

// 固定回调
var _pullback_fixed_startprice              = 0;                                // 开关变量(监测回调止盈机制是否开始)-多
var _pullback_fixed_switch                  = false;                            // 标记多单回调止盈已开始

var _PEAK_PRICE_IN_POSITIONS                = 0;                // 持仓中价格的峰值点(最高/最低点)

var _pullbakc_fixed_price_1                 = 0;                                // 多单回调止盈价格-1

var _pullbakc_fixed_price_2                 = 0;                                // 多单回调止盈价格-2

var _pullback_fixed_hastakeprofit           = false;                            // 已经止盈过,防止回调之后连续减仓

// 利润回调

var _pullback_profit_startprice             = 0;                                // 在什么利润百分比的时候开启利润回调止盈
var _pullback_profit_switch                 = false;                            // 利润回调止盈开关
var _pullback_profit_switch_2               = false;                            // 利润回调平仓开关


var _PEAK_PROFIT_IN_POSITIONS               = 0;                // 持仓中盈利的峰值点(最高/最低点)

var _pullback_profit_price                  = 0;                                // 利润回调止盈的利润百分比
var _pullback_profit_price_2                = 0;                                // 利润回调平仓的利润百分比

var _pullback_profit_hastakeprofit          = false;                            // 已经止盈过

var _pullback_profit_repeattimes            = 0;                                // 计算变量,回调止盈一次,则 + 1


// 时间戳--防止过度执行
var _PULLBACK_SLEEPTIME                     = 0;                                // 纳秒级时间戳,在开单和平单时(2秒内)保证回调止盈函数不执行                     






// 统计变量
var _init_asset                             = 0;                                        // 账户资产
var _profit_local                           = 0;                                        // 利润
var _take_profit_count                      = 0;                                        // 止盈次数
var _trade_count                            = 0;                                        // 交易次数
var _strategy_run_time_stamp_string         = "strategy_run_time";                      // 策略运行时间
var _strategy_datas                         = { start_run_timestamp: 0, others: "" };   // 策略开始时间
var _user_datas                             = null;                                     // 保存用户数据
var current_asset                           = 0;                                        // 当前资产(改为全局变量为了保证开单的数量准确)



// 相对固定参数
var _maintenance_margin_rate                = 0.004                                 // 维持保证金率
var _taker_fee                              = 0.0005;                               // 吃单手续费
var _is_USDT_standard                       = false;                                // USDT本位开单和结算


// 全局变量
var positions                               = null;              // 从交易所获取的仓位信息
var account                                 = null;              // 从交易所获取的账户信息
var ticker                                  = null;              // 从交易所获取的市场行情


var _base_margin;                                   // 初始杠杆
var _asset_precision                        = 0;                // 资产精度
var _asset_price_precision                  = 0;                // 价格精度
var DEFAULT_ASSET_PRECISION                 = 3;                // 资产精度默认值
var DEFAULT_PRICE_PRECISION                 = 2;                // 价格精度的默认值

var _has_open_long                          = false;            // 跟踪是否已经开过多单
var _has_open_short                         = false;            // 跟踪是否已经开过空单

var _TRIGGER_PULLBACK                       = false;            // 是否触发了回调止盈







// 保存程序起始运行时间 秒级时间戳
function _SaveStrategyRunTime() {
    var local_data_strategy_run_time = _G(_strategy_run_time_stamp_string);

    if (local_data_strategy_run_time == null) {
        _strategy_datas.start_run_timestamp = Unix();
        _G(_strategy_run_time_stamp_string, _strategy_datas.start_run_timestamp);
    }
    else {
        _strategy_datas.start_run_timestamp = local_data_strategy_run_time;
    }
}


// 设置程序起始运行时间 秒级时间戳
function _SetStrategyRunTime(timestamp) {
    _G(_strategy_run_time_stamp_string,   timestamp);
    _strategy_datas.start_run_timestamp = timestamp;
}


// 计算两个时间戳之间的天数,参数是秒级时间戳
function _GetDaysFromTimeStamp(start_time, end_time) {
    if (end_time < start_time)
        return 0;

    return Math.trunc((end_time - start_time) / (60 * 60 * 24));
}


// 保存数据到本地
function _SaveUserDatasLocal() {
    _user_datas = 
    {
        init_assets:        _init_asset,
        profit_local:       _profit_local,
        take_profit_count:  _take_profit_count,
        trade_count:        _trade_count
    };
    // 存储到本地
    _G(exchange.GetLabel(), _user_datas);
    Log("已把所有数据保存到本地.");
}


// 读取用户本地数据,程序启动时候运行一次
function _ReadUserDataLocal(positions, account, ticker) {
    var user_data       = _G(exchange.GetLabel());  //从本地获取用户数据

    if (user_data == null) 
    {//如果数据为空,则写入数据
        _init_asset = _GetAccountAsset(positions, account, ticker);

        _user_datas = {
            init_assets:        _init_asset,        //账户资产
            profit_local:       0,                  //账户利润
            take_profit_count:  0,                  //获利次数
            trade_count:        0                   //交易次数
        };
    } 
    else 
    {//如果数据不为空,则从本地获取数据
        _user_datas = user_data;                    //
    }

    Log("当前资金: ", _N(_GetAccountAsset(positions, account, ticker), 4));
}


// 清除用户本地数据,交互按钮点击运行
function _ClearUserDataLocal() 
{
    _G(exchange.GetLabel(), null);
    Log(exchange.GetLabel(), ": 已清除本地数据.");
}

//将购买数量调整为合适的精度: 
function _FixAmountPrecision(_amount, _amount_precision) 
{
    return parseFloat(_amount.toFixed(_amount_precision));
}

// 将价格调整到合适的精度
function _FixPricePrecision(_price, _price_precision) 
{
    return parseFloat(_price.toFixed(_price_precision));
}






// 状态栏信息打印
function _PrintLogStatus(positions, account, ticker) {
    var table_overview  = { type: 'table', title: '策略总览', cols: ['开始时间', '已运行天数', '交易次数', '胜率', '预估月化%', '预估年化%'], rows: [] };
    var table_account   = { type: 'table', title: '账户资金', cols: ['当前资产', '初始资产', '可用余额', '冻结余额', '可下单张数', '收益', '收益%'], rows: [] };
    var table_position = { type: 'table', title: '持仓情况', cols: ['交易币种', '杠杆', '数量', '保证金', '浮动盈亏', '% 浮动盈亏/最大盈利/利润止盈/回调平仓 %', '持仓价 / 当前价', '止损价格', '止盈价格', '固定回调'], rows: [] };

    // 策略总览打印
    var the_running_days = _GetDaysFromTimeStamp(_strategy_datas.start_run_timestamp, Unix());
    var monthly_rate_of_profit = 0;
    if (the_running_days > 1)
        monthly_rate_of_profit = _profit_local / _init_asset / the_running_days * 30;
    table_overview.rows.push([
        _D(_strategy_datas.start_run_timestamp * 1000),                                     //开始时间
        the_running_days,                                                                   //已运行天数
        _trade_count,                                                                       //交易次数
        _trade_count == 0 ? 0 : (_N(_take_profit_count / _trade_count * 100, 2) + "%"),     //胜率
        _N(monthly_rate_of_profit * 100, 2) + "%",                                          //预估月化%
        _N(monthly_rate_of_profit * 12 * 100, 2) + "%",                                     //预估年化%
    ]);


    // 账户资金打印
    current_asset   = _GetAccountAsset(positions, account, ticker);                  //获取账户资产
    var max_order_size  = _GetMaxOrderSize(positions, account, ticker, _margin_level);   //获取可开单张数
    var asset_profit = current_asset - _init_asset;
    var asset_profit_percent = asset_profit / _init_asset;
    table_account.rows.push([
        _N(current_asset, 4),                                                           //当前资产
        _N(_init_asset, 4),                                                             //初始资产
        _N(_is_USDT_standard ? account.Balance : account.Stocks, 4),                    //可用余额
        _N(_is_USDT_standard ? account.FrozenBalance : account.FrozenStocks, 4),        //冻结余额
        max_order_size,                                                                 //可下单张数
        _N(asset_profit, 4),                                                            //收益
        _N(asset_profit_percent * 100, 2) + "%"                                         //收益百分比
    ]);


    // 持仓情况打印
    var positions_direction         = "";   // 持仓方向
    var positions_profit_percent    = 0;    // 浮盈百分比
    var positions_profit            = 0;    // 浮盈
    var positions_margin            = 0;    // 保证金
    if (positions.length == 0) 
    {// 未持仓
        table_position.rows.push(["无持仓", "-", "-", "-", "-", "-", "-", "-", "-", "-"]);
    } 
    else
    {// 持仓状态
        positions_direction = positions[0].Type == PD_LONG ? "多单" : "空单";
        [positions_profit, positions_profit_percent] = _GetSinglepositionsProfit(positions, account, ticker);      //获取当前利润
        positions_margin = _GetSinglepositionsMargin(positions, account, ticker);                                  //获取当前仓位保证金

        table_position.rows.push([
            exchange.GetCurrency(),                                                                 // 交易币种
            _margin_level + "倍 / " + positions_direction,                                          // 杠杆倍数 + 方向
            positions[0].Amount,                                                                    // 数量
            _N(positions_margin, 4),                                                                // 保证金
            _N(positions_profit, 4),                                                                // 浮动盈亏
            _N((positions_profit_percent * 100), 2) + "% / " + _N(_PEAK_PROFIT_IN_POSITIONS, 2) + "% / " + _N(_pullback_profit_price, 2) + " % /" + _N(_pullback_profit_price_2, 2) + " %", // 浮动盈亏 + 最大盈利 + 利润回调止盈 + 利润回调平仓
            _N(positions[0].Price, 4) + " / " + _N(ticker.Last, 4),                                 // 持仓均价 + 当前价格
            _N(_stoploss_price, 4),                                                                 // 止损价格
            _N(_takeprofit_order_price_1, 4) + " / "  + _N(_takeprofit_order_price_2, 4) + " / "  + _N(_takeprofit_order_price_3, 4) + " / "  + _N(_takeprofit_order_price_4, 4) + " / "  + _N(_takeprofit_order_price_5, 4),        // 挂单止盈价格
            _N(_pullbakc_fixed_price_1, 4)      + " / "  + _N(_pullbakc_fixed_price_2, 4),          // 回调止盈  点位1价格 / 点位2 价格

        ]);
    }
    // 打印表格
    LogStatus(
          '`' + JSON.stringify(table_overview)  + '`\n'
        + '`' + JSON.stringify(table_account)   + '`\n'
        + '`' + JSON.stringify(table_position) + '`\n');
}






// 初始化数据
function _InitDatas(positions, account, ticker) {
    _SaveStrategyRunTime();
    _ReadUserDataLocal(positions, account, ticker);

    _init_asset         = _user_datas.init_assets;              //资产统计
    _profit_local       = _user_datas.profit_local;             //统计收益
    _take_profit_count  = _user_datas.take_profit_count;        //盈利次数
    _trade_count        = _user_datas.trade_count;              //交易次数
    current_asset       = _GetAccountAsset(positions, account, ticker) // 统计当前资产

    if (_order_by_margin) 
    {
        _GetRealOrderSize(-1, _order_size);
        Log("已经重新计算下单张数: ", _order_size);
    }
}


// 获取账户资产
function _GetAccountAsset(positions, account, ticker) {
    // 计算不同情况下的账户初始资产
    var account_asset = 0;
    var positions_margin = _GetSinglepositionsMargin(positions, account, ticker);

    if (_is_USDT_standard) 
    {// U本位资产统计
        if (positions.length > 0) 
        {// 持仓时
            account_asset = account.Balance + account.FrozenBalance + positions_margin;   // 资产 = 未锁定资产 + 锁定资产 + 仓位保证金
        } 
        else 
        {// 空仓时
            account_asset = account.Balance + account.FrozenBalance;                      // 资产 = 未锁定资产 + 锁定资产
        }
    } 
    else 
    {// 币本位资产统计
        if (positions.length > 0) 
        {// 持仓位时
            account_asset = account.Stocks + account.FrozenStocks + positions_margin;     // 资产 = 未锁定资产 + 锁定资产 + 仓位保证金
        } 
        else 
        {// 空仓时
            account_asset = account.Stocks + account.FrozenStocks;                        // 资产 = 未锁定资产 + 锁定资产
        }
    }

    return account_asset;
}








// 策略交互
function _RunCommand(command) {
    var positions = _C(exchange.GetPositions);      //获取当前交易所账户的持仓信息,并返回一个包含持仓信息的对象。
    var account   = _C(exchange.GetAccount);        //获取交易所账户信息
    var ticker    = _C(exchange.GetTicker);         //获取当前交易对的市场行情信息

        if (command.indexOf("FMZ_ClearLocalData") == 0) {
            // 清除本地数据
            _ClearUserDataLocal();
        } 
        else if (command.indexOf("FMZ_SaveLocalData") == 0) {
            // 保存数据到本地
            _SaveUserDatasLocal();
        } 
        else if (command.indexOf("FMZ_ClearLog") == 0) {
            // 清除日志
            LogReset(Number(3));
            Log("只保留3条日志,其他清除。")
        } 
        else if (command.indexOf("FMZ_OrderSize:") == 0) {
            // 修改下单张数
            if (_order_by_margin) {
                Log("已经使用保证金数量来下单,无法直接修改下单数量!");
            } else {
                var FMZ_order_size = Number(command.replace("FMZ_OrderSize:", ""));
                _order_size = FMZ_order_size;
                Log("下单张数已经修改为: ", _order_size);
            }
        } 
        else if (command.indexOf("FMZ_OrderMarginPercent:") == 0) {
            // 修改下单保证金百分比
            if (_order_by_margin) {
                var order_margin_percent = Number(command.replace("FMZ_OrderMarginPercent:", ""));
                _order_margin_percent = order_margin_percent;
                Log("下单保证金百分比: ", _order_margin_percent, "%");
            } else {
                Log("没有打开根据保证金数量下单,无法修改下单保证金百分比!");
            }
        }
        else if (command.indexOf("FMZ_OpenLong") == 0) {// 手动开多
            if (positions.length > 0 && positions[0].Type === PD_LONG) {
                Log("持有多仓,无法继续开仓");
            }
            else
            {
                _OpenPositions(1, 0, positions, account, ticker);
            }
        }
        else if (command.indexOf("FMZ_OpenShort") == 0) {// 手动开空
            if (positions.length > 0 && positions[0].Type === PD_SHORT) {
                Log("持有空仓,无法继续开仓");
            }
            else
            {
                _OpenPositions(0, 1, positions, account, ticker);
            }
        }
        else if (command.indexOf("FMZ_CloseLong") == 0) {// 手动平多
            if (positions.length > 0) {
                if (positions[0].Type === PD_LONG) {
                    _Cover_1();                                             // 快速平仓
                    _ResetVariables();                                      // 重置运算变量
                    _CalculateProfit(positions, account, ticker);           // 统计收益
                } else {
                    Log("当前持有空头仓位");
                }
            }
            else {
                Log("没有持仓,无法平多");
            }
        }
        else if  (command.indexOf("FMZ_CloseShort") == 0) {//手动平空
            if (positions.length > 0) {
                if (positions[0].Type === PD_SHORT) {
                    _Cover_1();                                             // 快速平仓
                    _ResetVariables();                                             // 重置运算变量
                    _CalculateProfit(positions, account, ticker);           // 统计收益
                } else {
                    Log("当前持有多头持仓");
                }
            } else {
                Log("没有持仓,无法平空");
            }
        }

}




// 重新计算下单数量
function _GetRealOrderSize(price, amount) 
{
    var ticker = _C(exchange.GetTicker)
    var real_price = price == -1 ? ticker.Last : price;
    //var asset = _N(_GetAccountAsset(positions, account, ticker), 4) //删除,为了保证开单数量的准确性换用 current_asset

    if (_order_by_margin)//如果按照保证金百分比下单 
    {
        if (_is_USDT_standard) {
            _order_size = _N(current_asset * (_order_margin_percent / 100) / real_price * _margin_level / _one_size_in_current_coin, _amount_precision);
        } else {
            _order_size = _N(current_asset * (_order_margin_percent / 100) * _margin_level * real_price / _quarter_one_size_value, _amount_precision);
        }
    } 
    else 
    {//如果按照用户输入订单数下单
        _order_size = amount;
    }
    Log("可开单数量:" + _order_size);
    return _order_size;
}

// 获取单向持仓的收益和收益%
function _GetSinglepositionsProfit(positions, account, ticker) {
    if (positions.length == 0)
        return [0, 0];

    var price = ticker.Last;
    var positions_margin = _GetSinglepositionsMargin(positions, account, ticker);

    var positions_profit_percent    = positions[0].Type == PD_LONG ? ((price - positions[0].Price) / positions[0].Price) * _margin_level : ((positions[0].Price - price) / positions[0].Price) * _margin_level;
    var positions_profit            = positions_margin * positions_profit_percent;

    return [positions_profit, positions_profit_percent];
}



// 计算最大可下单张数
function _GetMaxOrderSize(positions, account, ticker, margin_level)
{
    var max_order_size = 0;

    if (_is_USDT_standard) {
        max_order_size = account.Balance * margin_level / (_one_size_in_current_coin * ticker.Last);
    } else {
        max_order_size = account.Stocks * ticker.Last / _quarter_one_size_value * margin_level;
    }

    return _N(max_order_size, _amount_precision);
}

// 获取单个持仓占用保证金 
function _GetSinglepositionsMargin(positions, account, ticker) 
{
    var positions_margin = 0;

    if (positions.length > 0) 
    {
        if (_is_USDT_standard) {
            positions_margin = positions[0].Amount * _one_size_in_current_coin * ticker.Last / _margin_level;
        } else {
            positions_margin = positions[0].Amount * _quarter_one_size_value / ticker.Last / _margin_level;
        }
    }

    return positions_margin;
}

//// 设置合约
function _SetContract(trade_currency) 
{   
    

    _is_USDT_standard = _trade_currency.includes("USDT") ? true : false;
    if (!IsVirtual()) {
        // 实盘设置
        exchange.SetCurrency(_trade_currency);
        if (_use_quarter) {
            exchange.SetContractType("quarter");
        } else {
            exchange.SetContractType("swap");
        }
    } else {
        // 回测设置
        if (_is_USDT_standard) {
            exchange.SetContractType("swap");
        } else {
            exchange.SetContractType("quarter");
        }
    }
    
    //////////通过交易对手动解析数量精度//////////////////////////////////////
    var ticker = _C(exchange.GetTicker)
    // 获取交易对信息
    if (ticker) 
    {//通过Ticker,尝试手动解析精度
        var priceString = ticker.Last.toString();
        _price_precision = (priceString.split(".")[1] || "").length;
        Log("推测的价格精度: ", _price_precision);
    } 
    else 
    {
        Log("无法获取到交易对 ", trade_currency, " 的精度信息, 请手动设定");
    }
    
    //////////通过市场买单手动解析数量精度//////////////////////////////////////
    var depth = _C(exchange.GetDepth);
    var totalPrecision = 0;
    var sampleCount = 0;
    if (depth && depth.Bids.length > 0) {
        for (var i = 0; i < depth.Bids.length; i++) {
            var amountString = depth.Bids[i].Amount.toString();
            totalPrecision += (amountString.split(".")[1] || "").length;
            sampleCount++;
        }

        if (sampleCount > 0) {
            _amount_precision = Math.round(totalPrecision / sampleCount);
            Log("解析的数量精度: ", _amount_precision);
        }
    } else {
        Log("无法获取到交易对 ", trade_currency, " 的数量精度信息, 请手动设定");
    }
    //////////通过市场买单手动解析数量精度//////////////////////////////////////


    exchange.SetMarginLevel(_margin_level);
    exchange.SetPrecision(_price_precision, _amount_precision);
}


// 是否还够资金下单
function _IsEnoughAssetToOrder(order_size, positions, account, ticker) 
{
    var is_enough = true;
    var account = _C(exchange.GetAccount);

    if (_is_USDT_standard) {
        if (account.Balance < order_size * ticker.Last * _one_size_in_current_coin / _margin_level) 
        {
            is_enough = false;
        }
    } else {
        if (account.Stocks < order_size * _quarter_one_size_value / ticker.Last / _margin_level) 
        {
            is_enough = false;
        }
    }

    return is_enough;
}






//// 检查重启后是否存在多单或空单
function _Initialize(positions) {

    // 撤销重启之前的所有挂单
    _CancelAllOrders();

    // 检查重启后是否持有多单或空单,调整止损价格,并重新根据止盈价格挂止盈单
    //var positions = exchange.GetPositions();

    for (var i = 0; i < positions.length; i++) {
        if (positions[i].Type === PD_LONG || positions[i].Type === PD_LONG_YD) {
            _has_open_long                      = true;
            _positions_type                     = "Long";                                                                       // 记录订单方向,用于止盈

            // 止损-多
            _stoploss_price                     = _FixPricePrecision(positions[0].Price * (1 - _STOPLOSS_PRICEPERCENT / 100), _price_precision);                        // 更新止损价格

            // 固定回调
            _pullback_fixed_startprice          = positions[0].Price * (1 + _PULLBACK_FIXED_STARTPRICEPERCENT / 100);           // 更新开关变量
            _pullbakc_fixed_price_1             = 0;                                                                            // 更新止盈回调价格
            _pullbakc_fixed_price_2             = 0;                                                                            // 更新止盈回调价格
            _pullback_fixed_switch              = false;                                                                        // 标记多单回调止盈已开始
            _pullback_fixed_hastakeprofit       = false;                                                                        // 已经止盈过,防止回调之后连续减仓
                
            // 利润回调
            _pullback_profit_startprice         = positions[0].Price * (1 + _PULLBACK_PROFIT_STARTPRICEPERCENT / 100);          // 更新开关变量
            _pullback_profit_price              = 0;                                                                            // 更新利润回调止盈价格
            _pullback_profit_price_2            = 0;                                                                            // 更新利润回调平仓价格

            _pullback_profit_switch             = false;                                                                    // 关闭利润回调止盈开关
            _pullback_profit_switch_2           = false;                                                                    // 关闭利润回调平仓开关
            _pullback_profit_hastakeprofit      = false;                                                                        // 是否已经止盈过
            _pullback_profit_repeattimes        = 0;                                                                            // 计算变量,回调止盈一次,则 + 1

            // 打印信息-多
            Log("存在多单, 持仓价格: ", positions[0].Price, ",  止损价格: ", _N(_stoploss_price, 6));                             //输出开仓价格信息////输出开仓价格信息

            // 挂止盈单
            if(_TAKEPROFIT_ORDER_OPEN)
            {
                _MakeTakeProfitOrder(positions);
            }
        } 
        else if (positions[i].Type === PD_SHORT || positions[i].Type === PD_SHORT_YD) {
            _has_open_short                     = true;
            _positions_type                     = "Short";                                                                  // 记录订单方向,用于止盈

            // 止损
            _stoploss_price                     = _FixPricePrecision(positions[0].Price * (1 + _STOPLOSS_PRICEPERCENT / 100), _price_precision);                //更新止损价格

            // 固定回调
            _pullback_fixed_startprice          = positions[0].Price * (1 - _PULLBACK_FIXED_STARTPRICEPERCENT / 100);       // 开关变量
            _pullbakc_fixed_price_1             = 0;                                                                        // 更新止盈回调价格
            _pullbakc_fixed_price_2             = 0;                                                                        // 更新止盈回调价格
            _pullback_fixed_switch              = false;                                                                    // 标记多单回调止盈已开始
            _pullback_fixed_hastakeprofit       = false;                                                                    // 已经止盈过,防止回调之后连续减仓

            // 利润回调
            _pullback_profit_startprice         = positions[0].Price * (1 - _PULLBACK_PROFIT_STARTPRICEPERCENT / 100);      // 开关变量
            _pullback_profit_price              = 0;                                                                        // 更新利润回调止盈价格
            _pullback_profit_price_2            = 0;                                                                        // 更新利润回调平仓价格

            _pullback_profit_switch             = false;                                                                    // 关闭利润回调止盈开关
            _pullback_profit_switch_2           = false;                                                                    // 关闭利润回调平仓开关
            _pullback_profit_hastakeprofit      = false;                                                                    // 是否已经止盈过
            _pullback_profit_repeattimes        = 0;                                                                        // 计算变量,回调止盈一次,则 + 1

            ////输出开仓价格信息
            Log("存在空单, 持仓价格: ", positions[0].Price, ",  止损价格: ", _N(_stoploss_price, 6));      //输出开仓价格信息

            // 挂止盈单
            if(_TAKEPROFIT_ORDER_OPEN)
            {
                _MakeTakeProfitOrder(positions);
            }
        }
    }
}






//// 根据TV消息执行对应的操作
function _RunTVCommand(command) 
{
    ////
    var positions = _C(exchange.GetPositions);      //获取当前交易所账户的持仓信息,并返回一个包含持仓信息的对象。
    var account   = _C(exchange.GetAccount);        //获取交易所账户信息
    var ticker    = _C(exchange.GetTicker);         //获取当前交易对的市场行情信息

    var action          = command.Action; //获取要执行的处理

    if (positions.length > 1) {      ////如果同时持有多空仓位则退出
        Log(positions);
        throw "同时有多空持仓!无法操作";
    }


    switch (action) {
        case "OpenLong":        // 开多单
            _OpenPositions(1, 0, positions, account, ticker);
            break;
        case "OpenShort":       // 开空单
            _OpenPositions(0, 1, positions, account, ticker);
            break;
        case "CloseLong":       // TV信号平多
            if (positions.length > 0) {
                if (positions[0].Type === PD_LONG) {
                    _Cover_1();                                             // 快速平仓
                    _ResetVariables();                                             // 重置运算变量
                    _CalculateProfit(positions, account, ticker);           // 统计收益
                } else {
                    Log("当前持有空头仓位");
                }
            }
            else {
                Log("没有持仓,无法平多");
            }
            break;
        case "CloseShort":      //TV信号平空
            if (positions.length > 0) {
                if (positions[0].Type === PD_SHORT) {
                    _Cover_1();                                             // 快速平仓
                    _ResetVariables();                                             // 重置运算变量
                    _CalculateProfit(positions, account, ticker);           // 统计收益
                } else {
                    Log("当前持有多头持仓");
                }
            } else {
                Log("没有持仓,无法平空");
            }
            break;
        default:
            break;
    }
}







//// 根据订单方向下单
function _OpenPositions(long, short, positions, account, ticker) 
{
    var positions_size = positions.length > 0 ? positions[0].Amount : 0;
    var positions_type = positions.length > 0 ? positions[0].Type : null;

    if (long)////开多单
    {
        //判断是否持仓
        if (positions_size > 0 && positions_type == PD_SHORT) {             // 如果当前持有空仓
            _Cover_1();                                                     // 快速平仓
            _ResetVariables();                                                     // 重置运算变量
            _CalculateProfit(positions, account, ticker);                   // 统计收益
        }
        else if (positions_size > 0 && positions_type == PD_LONG) {         // 如果当前持有多仓
            Log("持有多单,不继续开多.");                                      // 多单持仓,不重复下单
            return;
        }
        else { }

        // 如果资金充足,则下单
        if (_IsEnoughAssetToOrder(_order_size, positions, account, ticker)) 
        {   
            _OpenLong(-1, _order_size);                 // 开多单
            Sleep(2000);                                // 等待一会儿

            var positions = _C(exchange.GetPositions)

            if (positions.length > 0) {
                _has_open_long                      = true;
                _positions_type                     = "Long";                                                                   // 记录订单方向,用于止盈

                // 止损-多
                _stoploss_price                     = _FixPricePrecision(positions[0].Price * (1 - _STOPLOSS_PRICEPERCENT / 100), _price_precision);                        // 更新止损价格

                // 固定回调
                _pullback_fixed_startprice          = positions[0].Price * (1 + _PULLBACK_FIXED_STARTPRICEPERCENT / 100);       // 更新开关变量
                _pullbakc_fixed_price_1             = 0;                                                                            // 更新止盈回调价格
                _pullbakc_fixed_price_2             = 0;                                                                            // 更新止盈回调价格
                _pullback_fixed_switch              = false;                                                                        // 标记多单回调止盈已开始
                _pullback_fixed_hastakeprofit       = false;                                                                        // 已经止盈过,防止回调之后连续减仓
                
                // 利润回调
                _pullback_profit_startprice         = positions[0].Price * (1 + _PULLBACK_PROFIT_STARTPRICEPERCENT / 100);      // 更新开关变量
                _pullback_profit_price              = 0;                                                                            // 更新利润回调止盈价格
                _pullback_profit_price_2            = 0;                                                                            // 更新利润回调平仓价格

                _pullback_profit_switch             = false;                                                                    // 关闭利润回调止盈开关
                _pullback_profit_switch_2           = false;                                                                    // 关闭利润回调平仓开关
                _pullback_profit_hastakeprofit      = false;                                                                        // 是否已经止盈过
                _pullback_profit_repeattimes        = 0;                                                                            // 计算变量,回调止盈一次,则 + 1

                // 打印信息
                Log("市价开多, 价格: ", positions[0].Price, ",  止损价格: ", _N(_stoploss_price, 6), ", 止盈价格:" + _N(_takeprofit_order_price_1, 6) + " / "+ _N(_takeprofit_order_price_2, 6));      //输出开仓价格信息////输出开仓价格信息
                
                // 挂止盈单
                if (_TAKEPROFIT_ORDER_OPEN)
                {
                    _MakeTakeProfitOrder(positions);
                }
            }
            else {
                Log("开多单失败。")
            }
        } 
        else // 资金不足
        {
            throw "保证金不足!";
        }
    } 
    else if (short) // 开空单
    {
        ////判断是否持仓
        if (positions_size > 0 && positions_type == PD_LONG) {              //如果当前持有多仓
            _Cover_1();                                                     // 快速平仓
            _ResetVariables();                                                     // 重置运算变量
            _CalculateProfit(positions, account, ticker);                   //统计收益
        } 
        else if (positions_size > 0 && positions_type == PD_SHORT) {
            Log("持有空单,不继续开空");                                      // 空单持仓,不重复下单
            return;
        } 
        else { }

        //// 如果资金充足,则下单
        if (_IsEnoughAssetToOrder(_order_size, positions, account, ticker)) 
        {
            _OpenShort(-1, _order_size);                //开空单
            Sleep(2000);                                // 等待一会儿

            var positions  = _C(exchange.GetPositions)

            if (positions.length > 0) {
                _has_open_short                     = true;
                _positions_type                     = "Short";                                                                  // 记录订单方向,用于止盈

                // 止损
                _stoploss_price                     = _FixPricePrecision(positions[0].Price * (1 + _STOPLOSS_PRICEPERCENT / 100), _price_precision);                //更新止损价格

                // 固定回调
                _pullback_fixed_startprice          = positions[0].Price * (1 - _PULLBACK_FIXED_STARTPRICEPERCENT / 100);       // 开关变量
                _pullbakc_fixed_price_1             = 0;                                                                        // 更新止盈回调价格
                _pullbakc_fixed_price_2             = 0;                                                                        // 更新止盈回调价格
                _pullback_fixed_switch              = false;                                                                    // 标记多单回调止盈已开始
                _pullback_fixed_hastakeprofit       = false;                                                                    // 已经止盈过,防止回调之后连续减仓

                // 利润回调
                _pullback_profit_startprice         = positions[0].Price * (1 - _PULLBACK_PROFIT_STARTPRICEPERCENT / 100);      // 开关变量
                _pullback_profit_price              = 0;                                                                        // 更新利润回调止盈价格
                _pullback_profit_price_2            = 0;                                                                        // 更新利润回调平仓价格

                _pullback_profit_switch             = false;                                                                    // 关闭利润回调止盈开关
                _pullback_profit_switch_2           = false;                                                                    // 关闭利润回调平仓开关

                _pullback_profit_hastakeprofit      = false;                                                                    // 是否已经止盈过
                _pullback_profit_repeattimes        = 0;                                                                        // 计算变量,回调止盈一次,则 + 1

                ////输出开仓价格信息
                Log("存在空单, 持仓价格: ", positions[0].Price, ",  止损价格: ", _N(_stoploss_price, 6));      //输出开仓价格信息

                // 挂止盈单
                if (_TAKEPROFIT_ORDER_OPEN)
                {
                    _MakeTakeProfitOrder(positions);
                }
            }
            else {
                Log("开空单失败。")
            }
        } 
        else // 资金不足
        {
            throw "保证金不足!";
        }
    }
}









//开多
function _OpenLong(price, amount) 
{   
    _ResetVariables();                                      // 重置运算变量
    _positions_type             = "Long";       // 更新订单方向
    return _OrderDirectly("buy", price, _order_size);
}

// 开空
function _OpenShort(price, amount) 
{
    _ResetVariables();                                      // 重置运算变量
    _positions_type             = "Short";      // 更新订单方向
    return _OrderDirectly("sell", price, _order_size);
}

// 平多(市价减仓)
function _ReduceLong(price, amount)
{
    var positions = _C(exchange.GetPositions);

    if (amount > 0)
    {
        if(positions[0].Amount < amount)
        {
            return _OrderDirectly("closebuy", price, positions[0].Amount);
        }
        else 
        {
            return _OrderDirectly("closebuy", price, amount);
        }
    }
    else
    {
        return null;
    }
        
}

//平空(市价减仓)
function _ReduceShort(price, amount) 
{//平仓空单
    var positions = _C(exchange.GetPositions);

    if (amount > 0)
    {
        if(positions[0].Amount < amount)
        {
            return _OrderDirectly("closesell", price, positions[0].Amount);
        }
        else
        {
            return _OrderDirectly("closesell", price, amount);
        }
    }
    else
    {
        return null;
    }
}
//// 平空(市价全平)
function _Cover_1() //止损平仓--只求速度
{
    var positions = _C(exchange.GetPositions);

    if (positions.length > 0 && positions[0].Type == PD_LONG)
    {
        return _OrderDirectly("closebuy", -1, positions[0].Amount);
    }
    else if (positions.length > 0 && positions[0].Type == PD_SHORT)
    {
        return _OrderDirectly("closesell", -1, positions[0].Amount);
    }
    else
    {return null;}
}
function _ResetVariables() //止损平仓--重置运算变量
{
    ////重置运算变量
    _order_size     = _GetRealOrderSize(-1, _order_size);
    ////运算变量
    _positions_type = null;                                         // 用于挂单止盈之后的收益展示

    // 止损
    _stoploss_price = 0;                                            // 止损价格,用于止损运算
    _had_stoploss = false;                                          // 已经达到止损价格

    // 挂单止盈
    _takeprofit_order_price_1 = 0;                                  // 挂单止盈价格-1
    _takeprofit_order_amount_1 = 0;                                 // 挂单止盈数量-1

    _takeprofit_order_price_2 = 0;                                  // 挂单止盈价格-2
    _takeprofit_order_amount_2 = 0;                                 // 挂单止盈数量-2

    _takeprofit_order_price_3 = 0;                                  // 挂单止盈价格-3
    _takeprofit_order_amount_3 = 0;                                 // 挂单止盈数量-3

    _takeprofit_order_price_4 = 0;                                  // 挂单止盈价格-4
    _takeprofit_order_amount_4 = 0;                                 // 挂单止盈数量-4

    _takeprofit_order_price_5 = 0;                                  // 挂单止盈价格-5
    _takeprofit_order_amount_5 = 0;                                 // 挂单止盈数量-5

    _takeprofit_order_id_1 = null;                                  // 记录止盈单ID
    _takeprofit_order_id_2 = null;                                  // 记录止盈单ID
    _takeprofit_order_id_3 = null;                                  // 记录止盈单ID
    _takeprofit_order_id_4 = null;                                  // 记录止盈单ID
    _takeprofit_order_id_5 = null;                                  // 记录止盈单ID
    
    _takeprofit_order_price_1   = 0;                                // 重置止盈价格1
    _takeprofit_order_price_2   = 0;                                // 重置止盈价格2
    _takeprofit_order_price_3   = 0;                                // 重置止盈价格3
    _takeprofit_order_price_4   = 0;                                // 重置止盈价格4
    _takeprofit_order_price_5   = 0;                                // 重置止盈价格5


    _takeprofit_order_hastakeprofit_1 = false;                      // 是否止盈过?  用于打印收益信息
    _takeprofit_order_hastakeprofit_2 = false;                      // 是否止盈过?  用于打印收益信息
    _takeprofit_order_hastakeprofit_3 = false;                      // 是否止盈过?  用于打印收益信息
    _takeprofit_order_hastakeprofit_4 = false;                      // 是否止盈过?  用于打印收益信息
    _takeprofit_order_hastakeprofit_5 = false;                      // 是否止盈过?  用于打印收益信息

    // 固定回调
    _pullback_fixed_startprice = 0;                                 // 开关变量(监测回调止盈机制是否开始)-多
    _pullback_fixed_switch = false;                                 // 标记多单回调止盈已开始

    _PEAK_PRICE_IN_POSITIONS = 0;                                   // 持仓中价格的峰值点(最高/最低点)

    _pullbakc_fixed_price_1 = 0;                                    // 多单回调止盈价格-1
    _pullbakc_fixed_price_2 = 0;                                    // 多单回调止盈价格-2

    _pullback_fixed_hastakeprofit = false;                          // 已经止盈过,防止回调之后连续减仓

    // 利润回调

    _pullback_profit_startprice = 0;                                // 在什么利润百分比的时候开启利润回调止盈
    _pullback_profit_switch = false;                                // 是否开始进行回调止盈
    _pullback_profit_switch_2 = false;                              // 关闭利润回调平仓

    _PEAK_PROFIT_IN_POSITIONS = 0;                                  // 持仓中价格的峰值点(最高/最低点)

    _pullback_profit_price   = 0;                                   // 利润回调减仓的利润值
    _pullback_profit_price_2 = 0;                                   // 利润回调平仓的利润值
    _pullback_profit_hastakeprofit          = false;                // 已经止盈过
    _pullback_profit_repeattimes = 0;                               // 计算变量,回调止盈一次,则 + 1
}

//// 平多(市价全平)
//function _CoverLong()
//{
//    var positions = _C(exchange.GetPositions);

//    _CancelAllOrders();                     //取消所有挂单

//    if (positions.length > 0 && positions[0].Type == PD_LONG)
//    {
//        return _OrderDirectly("closebuy", -1, positions[0].Amount);
//    }
//    else
//    {return null;}
//}

//// 平空(市价全平)
//*function _CoverShort()
//{// 平仓空单
//    var positions = _C(exchange.GetPositions);

//    _CancelAllOrders();                     //取消所有挂单
//
//    if (positions.length > 0 && positions[0].Type == PD_SHORT)
//    {
//        return _OrderDirectly("closesell", -1, positions[0].Amount);
//    }
//    else
//    {return null;}
//}


// 交易函数
function _OrderDirectly(distance, price, amount) 
{
    var tradeFunc = null;

    if (amount <= 0) {
        throw "设置的参数有误,下单数量已经小于0!"
    }

    if (distance == "buy") 
    {//开多
        tradeFunc = exchange.Buy;
    } 
    else if (distance == "sell") 
    {//开空
        tradeFunc = exchange.Sell;
    } 
    else if (distance == "closebuy") 
    {//市价平多
        tradeFunc = exchange.Sell;
        Log("多单市价平仓, 数量: ", amount);
    } 
    else if(distance == "closesell")
    {//市价平空
        tradeFunc = exchange.Buy;
        Log("空单市价平仓, 数量: ", amount);
    }
    
    exchange.SetDirection(distance);
    return tradeFunc(price, amount);
}


function _CancelAllOrders() {
    while (true) {
        var orders = exchange.GetOrders(); // 获取当前所有挂单
        if (!orders || orders.length === 0) {
            break; // 如果没有挂单,就退出循环
        }
        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id); // 取消每一个挂单
            Log("取消挂单: ", orders[i].Id); // 记录取消的挂单
            Sleep(10); // 等待,防止请求过于频繁
        }
    }
}



//// 仓位监测,进行止盈止损和回调止盈
function _PositionMonitoring()
{   
    ////这里必须要重新获取仓位、账户、市场信息,否则会报错
    var positions = _C(exchange.GetPositions);      //获取当前交易所账户的持仓信息,并返回一个包含持仓信息的对象。
    var account   = _C(exchange.GetAccount);        //获取交易所账户信息
    var ticker    = _C(exchange.GetTicker);         //获取当前交易对的市场行情信息


    _PrintLogStatus(positions, account, ticker);    // 状态栏信息打印

    // 监控止损
    if (_stoploss_price > 0) {                                                  // 如果止损价格不为空
        _StopLoss(positions, account, ticker);                                  // 调用对应函数
    }

    // 监控挂单止盈是否成交
    // 如果机制开启了,并且持有仓位,并且某一个挂单止盈价格不为空
    if (_TAKEPROFIT_ORDER_OPEN && (_takeprofit_order_price_1 > 0 || _takeprofit_order_price_2 > 0 || _takeprofit_order_price_3 > 0 || _takeprofit_order_price_4 > 0 || _takeprofit_order_price_5 > 0)) 
    {       
        _TakeProfit(positions, account, ticker);                                // 调用对应函数
    }
    
    positions = _C(exchange.GetPositions);                                      //重新获取仓位信息,防止监控时出现仓位为0的问题
    // 监控固定回调止盈
    if (_PULLBACK_FIXED_OPEN && positions.length > 0) {                         // 如果持有仓位,且启用了固定回调止盈机制
        _PullbackTakeProfit_Fixed(positions, account, ticker);                  // 调用对应函数
    }

    // 监控利润回调止盈
    if (_PULLBACK_PROFIT_OPEN && positions.length > 0) {                        // 如果持有仓位,且启用了利润回调止盈机制
        _PullbackTakeProfit_Profit(positions, account, ticker);                 // 调用对应函数
    }
}


// 挂空单止盈单
function _MakeTakeProfitOrder(positions) {
    if (_TAKEPROFIT_ORDER_OPEN && _positions_type == "Long" || positions[0].Type === PD_LONG) {
        // 挂单止盈-多
        _takeprofit_order_price_1   = _FixPricePrecision(positions[0].Price * (1 + _TAKEPROFIT_ORDER_PRICEPERCENT_1 / 100), _price_precision);              // 止盈价格-1
        _takeprofit_order_amount_1  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_1 / 100, _amount_precision);                // 止盈数量-1

        _takeprofit_order_price_2   = _FixPricePrecision(positions[0].Price * (1 + _TAKEPROFIT_ORDER_PRICEPERCENT_2 / 100), _price_precision);              // 止盈价格-2
        _takeprofit_order_amount_2  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_2 / 100, _amount_precision);                // 止盈数量-2

        _takeprofit_order_price_3   = _FixPricePrecision(positions[0].Price * (1 + _TAKEPROFIT_ORDER_PRICEPERCENT_3 / 100), _price_precision);              // 止盈价格-3
        _takeprofit_order_amount_3  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_3 / 100, _amount_precision);                // 止盈数量-3

        _takeprofit_order_price_4   = _FixPricePrecision(positions[0].Price * (1 + _TAKEPROFIT_ORDER_PRICEPERCENT_4 / 100), _price_precision);              // 止盈价格-4
        _takeprofit_order_amount_4  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_4 / 100, _amount_precision);                // 止盈数量-4

        _takeprofit_order_price_5   = _FixPricePrecision(positions[0].Price * (1 + _TAKEPROFIT_ORDER_PRICEPERCENT_5 / 100), _price_precision);              // 止盈价格-5
        _takeprofit_order_amount_5  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_5 / 100, _amount_precision);                // 止盈数量-5

        _takeprofit_order_hastakeprofit_1           = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_2           = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_3           = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_4           = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_5           = false;                 // 标记止盈,防止信息重复发送

        // 挂多单止盈单-1
        try {
            Log("多 --> 挂止盈单-1,价格: ", _takeprofit_order_price_1, ",  数量: ", _takeprofit_order_amount_1);     // 输出日志
            exchange.SetDirection("closebuy");                                                  // 设置止盈平多交易方向
            _takeprofit_order_id_1 = exchange.Sell(_takeprofit_order_price_1, _takeprofit_order_amount_1);     // 挂止盈单
        }
        catch (error) {
            Log("多 --> 挂止盈单-1,失败: ", error.message, "错误详情: ", error);
            _takeprofit_order_id_1 = null;
        }

        // 挂多单止盈单-2
        try {
            Log("多 --> 挂止盈单-2,价格: ", _takeprofit_order_price_2, ",  数量: ", _takeprofit_order_amount_2);     // 输出日志
            exchange.SetDirection("closebuy");                                                  // 设置止盈平多交易方向
            _takeprofit_order_id_2 = exchange.Sell(_takeprofit_order_price_2, _takeprofit_order_amount_2);     // 挂止盈单
        }
        catch (error) {
            Log("多 --> 挂止盈单-2,失败: ", error.message, "错误详情: ", error);
            _takeprofit_order_id_2 = null;
        }

        // 挂多单止盈单-3
        try {
            Log("多 --> 挂止盈单-3,价格: ", _takeprofit_order_price_3, ",  数量: ", _takeprofit_order_amount_3);     // 输出日志
            exchange.SetDirection("closebuy");                                                  // 设置止盈平多交易方向
            _takeprofit_order_id_3 = exchange.Sell(_takeprofit_order_price_3, _takeprofit_order_amount_3);     // 挂止盈单
        }
        catch (error) {
            Log("多 --> 挂止盈单-3,失败: ", error.message, "错误详情: ", error);
            _takeprofit_order_id_3 = null;
        }

        // 挂多单止盈单-4
        try {
            Log("多 --> 挂止盈单-4,价格: ", _takeprofit_order_price_4, ",  数量: ", _takeprofit_order_amount_4);     // 输出日志
            exchange.SetDirection("closebuy");                                                  // 设置止盈平多交易方向
            _takeprofit_order_id_4 = exchange.Sell(_takeprofit_order_price_4, _takeprofit_order_amount_4);     // 挂止盈单
        }
        catch (error) {
            Log("多 --> 挂止盈单-4,失败: ", error.message, "错误详情: ", error);
            _takeprofit_order_id_4 = null;
        }

        // 挂多单止盈单-5
        try {
            Log("多 --> 挂止盈单-5,价格: ", _takeprofit_order_price_5, ",  数量: ", _takeprofit_order_amount_5);     // 输出日志
            exchange.SetDirection("closebuy");                                                  // 设置止盈平多交易方向
            _takeprofit_order_id_5 = exchange.Sell(_takeprofit_order_price_5, _takeprofit_order_amount_5);     // 挂止盈单
        }
        catch (error) {
            Log("多 --> 挂止盈单-5,失败: ", error.message, "错误详情: ", error);
            _takeprofit_order_id_5 = null;
        }
    }
    else if (_TAKEPROFIT_ORDER_OPEN && _positions_type == "Short" || positions[0].Type === PD_SHORT) {
        // 挂单止盈
        _takeprofit_order_price_1   = _FixPricePrecision(positions[0].Price * (1 - _TAKEPROFIT_ORDER_PRICEPERCENT_1 / 100), _price_precision);      // 止盈价格-1
        _takeprofit_order_amount_1  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_1 / 100, _amount_precision);        // 止盈数量-1

        _takeprofit_order_price_2   = _FixPricePrecision(positions[0].Price * (1 - _TAKEPROFIT_ORDER_PRICEPERCENT_2 / 100), _price_precision);      // 止盈价格-2
        _takeprofit_order_amount_2  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_2 / 100, _amount_precision);        // 止盈数量-2

        _takeprofit_order_price_3   = _FixPricePrecision(positions[0].Price * (1 - _TAKEPROFIT_ORDER_PRICEPERCENT_3 / 100), _price_precision);      // 止盈价格-3
        _takeprofit_order_amount_3  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_3 / 100, _amount_precision);        // 止盈数量-3

        _takeprofit_order_price_4   = _FixPricePrecision(positions[0].Price * (1 - _TAKEPROFIT_ORDER_PRICEPERCENT_4 / 100), _price_precision);      // 止盈价格-4
        _takeprofit_order_amount_4  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_4 / 100, _amount_precision);        // 止盈数量-4

        _takeprofit_order_price_5   = _FixPricePrecision(positions[0].Price * (1 - _TAKEPROFIT_ORDER_PRICEPERCENT_5 / 100), _price_precision);      // 止盈价格-5
        _takeprofit_order_amount_5  = _FixAmountPrecision(positions[0].Amount * _TAKEPROFIT_ORDER_AMOUNTPERCENT_5 / 100, _amount_precision);        // 止盈数量-5

        _takeprofit_order_hastakeprofit_1       = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_2       = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_3       = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_4       = false;                 // 标记止盈,防止信息重复发送
        _takeprofit_order_hastakeprofit_5       = false;                 // 标记止盈,防止信息重复发送

        // 挂空单止盈单
        try {// 挂空单止盈单-1
            Log("空 --> 挂止盈单-1,价格: ", _takeprofit_order_price_1, ",  数量: ", _takeprofit_order_amount_1);         //输出日志
            exchange.SetDirection("closesell");                                                     //设置止盈平多交易方向
            _takeprofit_order_id_1 = exchange.Buy(_takeprofit_order_price_1, _takeprofit_order_amount_1);          //挂止盈单
        }
        catch (error) {
            Log("空 --> 挂止盈单-1,失败: ", error.message, ",  错误详情: ", error);
            _takeprofit_order_id_1 = null;
        }
        try {// 挂空单止盈单-2
            Log("空 --> 挂止盈单-2,价格: ", _takeprofit_order_price_2, ",  数量: ", _takeprofit_order_amount_2);         //输出日志
            exchange.SetDirection("closesell");                                                     //设置止盈平多交易方向
            _takeprofit_order_id_2 = exchange.Buy(_takeprofit_order_price_2, _takeprofit_order_amount_2);          //挂止盈单  
        }
        catch (error) {
            Log("空 --> 挂止盈单-2,失败: ", error.message, ",  错误详情: ", error);
            _takeprofit_order_id_2 = null;
        }
        try {// 挂空单止盈单-3
            Log("空 --> 挂止盈单-3,价格: ", _takeprofit_order_price_3, ",  数量: ", _takeprofit_order_amount_3);         //输出日志
            exchange.SetDirection("closesell");                                                     //设置止盈平多交易方向
            _takeprofit_order_id_3 = exchange.Buy(_takeprofit_order_price_3, _takeprofit_order_amount_3);          //挂止盈单
        }
        catch (error) {
            Log("空 --> 挂止盈单-3,失败: ", error.message, ",  错误详情: ", error);
            _takeprofit_order_id_3 = null;
        }
        try {// 挂空单止盈单-4
            Log("空 --> 挂止盈单-4,价格: ", _takeprofit_order_price_4, ",  数量: ", _takeprofit_order_amount_4);         //输出日志
            exchange.SetDirection("closesell");                                                     //设置止盈平多交易方向
            _takeprofit_order_id_4 = exchange.Buy(_takeprofit_order_price_4, _takeprofit_order_amount_4);          //挂止盈单
        }
        catch (error) {
            Log("空 --> 挂止盈单-4,失败: ", error.message, ",  错误详情: ", error);
            _takeprofit_order_id_4 = null;
        }
        try {// 挂空单止盈单-5
            Log("空 --> 挂止盈单-5,价格: ", _takeprofit_order_price_5, ",  数量: ", _takeprofit_order_amount_5);         //输出日志
            exchange.SetDirection("closesell");                                                     //设置止盈平多交易方向
            _takeprofit_order_id_5 = exchange.Buy(_takeprofit_order_price_5, _takeprofit_order_amount_5);          //挂止盈单
        }
        catch (error) {
            Log("空 --> 挂止盈单-5,失败: ", error.message, ",  错误详情: ", error);
            _takeprofit_order_id_5 = null;
        }
    }
}



//// 检测挂单止盈是否成交
function _TakeProfit(positions, account, ticker) {
    var price = ticker.Last;

    if (_TAKEPROFIT_ORDER_OPEN && _positions_type == "Long")  {
        if(price > _takeprofit_order_price_1 && _takeprofit_order_hastakeprofit_1 == false)
        {
            Log("多 --> 止盈单-1,成交,价格: ", _N(_takeprofit_order_price_1, 6) + ", 数量: " + _N(_takeprofit_order_amount_1, 4));   // 日志输出

            _takeprofit_order_id_1                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_1           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_1                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
        if(price > _takeprofit_order_price_2 && _takeprofit_order_hastakeprofit_2 == false)
        {
            Log("多 --> 止盈单-2,价格: ", _N(_takeprofit_order_price_2, 6) + ", 数量: " + _N(_takeprofit_order_amount_2, 4));   // 输出

            _takeprofit_order_id_2                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_2           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_2                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       // 统计收益
        }
        if(price > _takeprofit_order_price_3 && _takeprofit_order_hastakeprofit_3 == false)
        {
            Log("多 --> 止盈单-3,成交,价格: ", _N(_takeprofit_order_price_3, 6) + ", 数量: " + _N(_takeprofit_order_amount_3, 4));   // 输出

            _takeprofit_order_id_3                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_3           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_3                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       // 统计收益
        }
        if(price > _takeprofit_order_price_4 && _takeprofit_order_hastakeprofit_4 == false)
        {
            Log("多 --> 止盈单-4,成交,价格: ", _N(_takeprofit_order_price_4, 6) + ", 数量: " + _N(_takeprofit_order_amount_4, 4));   // 输出

            _takeprofit_order_id_4                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_4           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_4                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       // 统计收益
        }
        if(price > _takeprofit_order_price_5 && _takeprofit_order_hastakeprofit_5 == false)
        {
            Log("多 --> 止盈单-5,成交,价格: ", _N(_takeprofit_order_price_5, 6) + ", 数量: " + _N(_takeprofit_order_amount_5, 4));   // 输出

            _takeprofit_order_id_5                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_5           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_5                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       // 统计收益
        }
    }


    ////空单止盈
    else if (_TAKEPROFIT_ORDER_OPEN && _positions_type == "Short") {
        if(price < _takeprofit_order_price_1 && _takeprofit_order_hastakeprofit_1 == false)
        {
            Log("空 --> 止盈单-1,成交,价格:  ", _N(_takeprofit_order_price_1, 6) + ", 数量: " + _N(_takeprofit_order_amount_1, 4));

            _takeprofit_order_id_1                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_1           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_1                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
        if(price < _takeprofit_order_price_2 && _takeprofit_order_hastakeprofit_2 == false)
        {
            Log("空 --> 止盈单-2,成交,价格:  ", _N(_takeprofit_order_price_2, 6) + ", 数量: " + _N(_takeprofit_order_amount_2, 4));

            _takeprofit_order_id_2                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_2           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_2                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
        if(price < _takeprofit_order_price_3 && _takeprofit_order_hastakeprofit_3 == false)
        {
            Log("空 --> 止盈单-3,成交,价格:  ", _N(_takeprofit_order_price_3, 6) + ", 数量: " + _N(_takeprofit_order_amount_3, 4));

            _takeprofit_order_id_3                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_3           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_3                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
        if(price < _takeprofit_order_price_4 && _takeprofit_order_hastakeprofit_4 == false)
        {
            Log("空 --> 止盈单-4,成交,价格:  ", _N(_takeprofit_order_price_4, 6) + ", 数量: " + _N(_takeprofit_order_amount_4, 4));

            _takeprofit_order_id_4                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_4           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_4                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
        if(price < _takeprofit_order_price_5 && _takeprofit_order_hastakeprofit_5 == false)
        {
            Log("空 --> 止盈单-5,成交,价格:  ", _N(_takeprofit_order_price_5, 6) + ", 数量: " + _N(_takeprofit_order_amount_5, 4));

            _takeprofit_order_id_5                      = null;                 // 清空止盈单ID
            _takeprofit_order_hastakeprofit_5           = true;                 // 标记止盈,防止信息重复发送
            _takeprofit_order_price_5                   = 0;                    // 重置止盈价格

            _CalculateProfit(positions, account, ticker);                       //统计收益
        }
    }
}


// 止损(市价止损)
function _StopLoss(positions, account, ticker) 
{   
    var price = ticker.Last;

    if (positions.length > 0 && positions[0].Type == PD_LONG) {
        if (price < _stoploss_price) {
            Log("多单止损, 全部平仓")
            Log("止损价格: ", _N(_stoploss_price, 6), ", 持仓价格: ", _N(positions[0].Price));
            _Cover_1();                                         // 快速平仓
            _ResetVariables();                                         // 重置变量
            _CalculateProfit(positions, account, ticker);       //统计收益

        }
    }
    else if (positions.length > 0 && positions[0].Type == PD_SHORT) {
        if (price > _stoploss_price) {          
            Log("空单止损, 全部平仓")
            Log("止损价格: ", _N(_stoploss_price, 6), ", 持仓价格: ", _N(positions[0].Price));
            _Cover_1();                                         // 快速平仓
            _ResetVariables();                                         // 重置变量
            _CalculateProfit(positions, account, ticker);       //统计收益
        }
    }
}



//// 回调止盈(固定回调)
function _PullbackTakeProfit_Fixed(positions, account, ticker)
{
    var price = ticker.Last;

    if (positions[0].Type == PD_LONG && _positions_type == "Long") {    // 开仓之后两秒,才执行这个检测

        if(price > _pullback_fixed_startprice && _pullback_fixed_switch == false )
        {
            Log("多 --> 固定回调止盈开启。当前价格:" + _N(positions[0].Price, 6));           // 开始回调止盈时发出一条消息
            _PEAK_PRICE_IN_POSITIONS    = price;      // 开始时记录价格低点

            _pullback_fixed_switch      = true;
        }

        if(_pullback_fixed_switch)
        {
            // 已达到触发价格,监控是否止盈
            _PEAK_PRICE_IN_POSITIONS        = price > _PEAK_PRICE_IN_POSITIONS ? price : _PEAK_PRICE_IN_POSITIONS;      // 更新价格高点
            _pullbakc_fixed_price_1         = _PEAK_PRICE_IN_POSITIONS * (1 - _PULLBACK_FIXED_PRICEPERCENT_1 / 100);         // 计算回调的止盈价格(使用的是交易对价格回撤百分比)
            _pullbakc_fixed_price_2         = _PEAK_PRICE_IN_POSITIONS * (1 - _PULLBACK_FIXED_PRICEPERCENT_2 / 100);         // 计算回调的止盈价格(使用的是交易对价格回撤百分比)
            //_PULLBACK_PROFIT_PRICE_11       = take_profit_price_11;                                                 // 用于打印回调止盈价格
            //_PULLBACK_PROFIT_PRICE_12       = take_profit_price_12;                                                 // 用于打印回调止盈价格

            if (price < _pullbakc_fixed_price_1 && _pullback_fixed_hastakeprofit == false) {// 达到回调止盈点位1,则部分减仓
                var amount  = _FixAmountPrecision(_order_size * _PULLBACK_FIXED_AMOUNTPERCENT_1 / 100, _amount_precision);        // 止盈数量(下单量的百分比)
                Log("多 --> 固定回调平仓 1, 数量: " + amount);
                Log(
                    "价格高点: ",   _N(_PEAK_PRICE_IN_POSITIONS, 6),
                    ", 回调价格: ", _N(_pullbakc_fixed_price_1, 6),
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息
                
                _ReduceLong(-1, amount);       // 多单减仓

                _CalculateProfit(positions, account, ticker);           //统计收益
                _pullback_fixed_hastakeprofit				= true;     // 是否止盈过一次,防止回调之后连续减仓
            }

            if (price < _pullbakc_fixed_price_2) {// 达到回调止盈点位2,则完全平仓
                
                Log("多 --> 固定回调平仓 2,当前持仓全部清空。");
                Log(
                    "价格高点: ",   _N(_PEAK_PRICE_IN_POSITIONS, 6),
                    ", 回调价格: ", _N(_pullbakc_fixed_price_2, 6),
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _Cover_1();                                             // 快速平仓
                _ResetVariables();                                             // 重置运算变量
                _CalculateProfit(positions, account, ticker);           // 统计收益    
            }
        }
    }
    else if (positions[0].Type == PD_SHORT && _positions_type == "Short") {//开仓之后两秒才执行这个检测

        if(price < _pullback_fixed_startprice && _pullback_fixed_switch == false)
        {
            Log("空 --> 固定回调止盈开启。当前价格:" + _N(positions[0].Price, 6));     // 开始回调止盈时发出一条消息
            _PEAK_PRICE_IN_POSITIONS        = price;                    // 开始时记录价格低点

            _pullback_fixed_switch          = true;
        }

        if(_pullback_fixed_switch)
        {
            // 空单已达到触发价格,监控是否止盈
            _PEAK_PRICE_IN_POSITIONS = price < _PEAK_PRICE_IN_POSITIONS ? price : _PEAK_PRICE_IN_POSITIONS;     // 更新价格低点
            _pullbakc_fixed_price_1 = _PEAK_PRICE_IN_POSITIONS * (1 + _PULLBACK_FIXED_PRICEPERCENT_1 / 100);                   // 计算回调的止盈价格
            _pullbakc_fixed_price_2 = _PEAK_PRICE_IN_POSITIONS * (1 + _PULLBACK_FIXED_PRICEPERCENT_2 / 100);                   // 计算回调的止盈价格

            //_PULLBACK_PROFIT_PRICE_11 = take_profit_price_11;                                                     // 用于打印回调止盈价格
            //_PULLBACK_PROFIT_PRICE_12 = take_profit_price_12;                                                     // 用于打印回调止盈价格


            if (price > _pullbakc_fixed_price_1 && _pullback_fixed_hastakeprofit == false) {// 达到回调止盈点位1,则部分减仓
                var amount  = _FixAmountPrecision(_order_size * _PULLBACK_FIXED_AMOUNTPERCENT_1 / 100, _amount_precision);        // 止盈数量(下单量的百分比)
                Log("空 --> 固定回调平仓 1, 数量: " + amount);
                Log(
                    "价格低点: ", _N(_PEAK_PRICE_IN_POSITIONS, 6),
                    ", 回调价格: ", _N(_pullbakc_fixed_price_1, 6),
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _ReduceShort(-1,amount);       // 空单减仓

                _CalculateProfit(positions, account, ticker);           // 统计收益
                _pullback_fixed_hastakeprofit = true;                   // 是否止盈过一次,防止回调之后连续减仓
            }

            if (price > _pullbakc_fixed_price_2) {// 达到回调止盈点位2,则完全平仓

                Log("空 --> 固定回调平仓 2,当前持仓全部清空。");
                Log(
                    "价格低点: ", _N(_PEAK_PRICE_IN_POSITIONS, 6),
                    ", 回调价格: ", _N(_pullbakc_fixed_price_2, 6),
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _Cover_1();                                             // 快速平仓
                _ResetVariables();                                             // 重置运算变量
                _CalculateProfit(positions, account, ticker);           // 统计收益
            }
        }
        
    }
}




//// 回调止盈(利润回调)
function _PullbackTakeProfit_Profit(positions, account, ticker) 
{
    var price = ticker.Last;
    var positions_profit_percent    = 100 * (positions[0].Type == PD_LONG ? ((price - positions[0].Price) / positions[0].Price) * _margin_level : ((positions[0].Price - price) / positions[0].Price) * _margin_level);

    if (positions[0].Type == PD_LONG && _positions_type == "Long") {// 开仓之后两秒才执行这个检测

        // 如果当前价格 > 利润回调止盈价格,且回调止盈开关未开启,且止盈次数 < 最大止盈次数,且当前利润 > 利润峰值
        if( price > _pullback_profit_startprice 
            && _pullback_profit_switch == false 
            && _pullback_profit_repeattimes < _PULLBACK_PROFIT_MAXREPEATTIMES
            && positions_profit_percent > _PEAK_PROFIT_IN_POSITIONS )
        {
            Log("多 --> 利润回调止盈第 " + (_pullback_profit_repeattimes + 1) + " 次开启。当前利润:"  + _N(positions_profit_percent, 2) + "%");        // 开始回调止盈时发出一条消息
            _PEAK_PROFIT_IN_POSITIONS           = positions_profit_percent;                         // 开始时记录盈利点
            _pullback_profit_switch             = true;                                             // 打开利润回调止盈开关
            _pullback_profit_switch_2           = true;                                             // 打开利润回调平仓开关

            _pullback_profit_hastakeprofit      = false;                                            // 利润回调再次进行
        }
        // 如果利润回调开关已打开,且回调止盈次数 < 最大止盈次数
        if(_pullback_profit_switch && _pullback_profit_repeattimes <= _PULLBACK_PROFIT_MAXREPEATTIMES) // 回调止盈已开启,且当前止盈次数 小于 最多止盈次数
        {
            // 多单已达到触发价格,监控是否止盈
            _PEAK_PROFIT_IN_POSITIONS   = positions_profit_percent > _PEAK_PROFIT_IN_POSITIONS ? positions_profit_percent : _PEAK_PROFIT_IN_POSITIONS;      // 更新仓位利润高点
            _pullback_profit_price      = _PEAK_PROFIT_IN_POSITIONS * (100 - _PULLBACK_PROFIT_MULT_1 * Math.pow(1/_PEAK_PROFIT_IN_POSITIONS * 2000000,1/3)) / 100;              // 计算回调止盈价格(利润百分比) 
            _pullback_profit_price_2    = _PEAK_PROFIT_IN_POSITIONS * (100 - _PULLBACK_PROFIT_MULT_2 * Math.pow(1/_PEAK_PROFIT_IN_POSITIONS * 2000000,1/3)) / 100;              // 计算回调清仓价格(利润百分比) 
            //_pullback_profit_price      = _PEAK_PROFIT_IN_POSITIONS * (1 - _PULLBACK_PROFIT_PRICEPERCENT / 100);                                          // 计算仓位利润的回调点

            if (positions_profit_percent < _pullback_profit_price && _pullback_profit_hastakeprofit == false) {// 达到回调止盈点位1,则部分减仓
                var amount  = _FixAmountPrecision(_order_size * _PULLBACK_PROFIT_AMOUNTPERCEHT / 100, _amount_precision);        // 止盈数量(下单量的百分比)
                Log("多 --> 利润回调第" + (_pullback_profit_repeattimes + 1) + "次减仓,数量: " + amount);
                Log(
                    "最高利润: ", _N(_PEAK_PROFIT_IN_POSITIONS , 2) + "%",
                    ", 当前利润: ", _N(positions_profit_percent, 2) + "%",
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _ReduceLong(-1, amount);                                // 多单减仓
                _CalculateProfit(positions, account, ticker);           //统计收益

                //_PEAK_PROFIT_IN_POSITIONS           = _PEAK_PROFIT_IN_POSITIONS * (1 - Math.sqrt(_PULLBACK_PROFIT_PRICEPERCENT) / 100)   //峰值下降一点
                _PEAK_PROFIT_IN_POSITIONS           = _PEAK_PROFIT_IN_POSITIONS * 0.97;                                             // 止盈之后,利润峰值下降一点
                _pullback_profit_hastakeprofit      = true;                                                                         // 已经止盈过了
                _pullback_profit_repeattimes        += 1;                                                                           // 执行了一次止盈回调,次数+1
                _pullback_profit_switch             = false;                                                                        //  利润回调之后要关一下开关
                _pullback_profit_price              = 0;                                                                            // 重置利润回调止盈

                if(_pullback_profit_repeattimes >= _PULLBACK_PROFIT_MAXREPEATTIMES)
                {
                    Log("利润回调止盈次数已用尽。");          //次数用尽消息
                }
            }
        }

        // 回调清仓
        // 启用了回调止盈平仓,并且临时开关打开了,并且当前利润 < 平仓利润
        if (_PULLBACK_PROFIT_OPEN_2 && _pullback_profit_switch_2 && positions_profit_percent < _pullback_profit_price_2) {// 达到回调止盈点位2,则完全平仓
                
                Log("多 --> 利润回调平仓,当前持仓全部清空。");
                Log(
                    "最高利润: ",   _N(_PEAK_PROFIT_IN_POSITIONS , 2) + "%",
                    ", 当前利润: ", _N(positions_profit_percent, 2) + "%",
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _Cover_1();                                             // 快速平仓
                _ResetVariables();                                             // 重置运算变量
                _CalculateProfit(positions, account, ticker);           // 统计收益    
            } 
        
    }
    else if (positions[0].Type == PD_SHORT && _positions_type == "Short") {// 开仓之后两秒才执行这个检测

        // 如果当前价格 < 利润回调止盈价格,且回调止盈开关未开启,且止盈次数 < 最大止盈次数,且当前利润 > 利润峰值
        if( price < _pullback_profit_startprice 
            && _pullback_profit_switch == false
            && _pullback_profit_repeattimes < _PULLBACK_PROFIT_MAXREPEATTIMES
            && positions_profit_percent > _PEAK_PROFIT_IN_POSITIONS )
        {
            Log("空 --> 利润回调止盈第 " + (_pullback_profit_repeattimes + 1) + " 次开启。当前利润:"  + _N(positions_profit_percent, 2) + "%");        // 开始回调止盈时发出一条消息
            _PEAK_PROFIT_IN_POSITIONS           = positions_profit_percent;                         // 记录开始时盈利百分比
            _pullback_profit_switch             = true;                                             // 打开利润回调止盈开关
            _pullback_profit_switch_2           = true;                                             // 打开利润回调平仓开关

            _pullback_profit_hastakeprofit      = false;                                            // 利润回调再次进行
        }

        if(_pullback_profit_switch && _pullback_profit_repeattimes < _PULLBACK_PROFIT_MAXREPEATTIMES)      // 回调止盈已开启,且当前止盈次数 小于 最多止盈次数
        {
            // 空单已达到触发价格,监控是否止盈
            _PEAK_PROFIT_IN_POSITIONS   = positions_profit_percent > _PEAK_PROFIT_IN_POSITIONS ? positions_profit_percent : _PEAK_PROFIT_IN_POSITIONS;      // 更新盈利高点
            _pullback_profit_price      = _PEAK_PROFIT_IN_POSITIONS * (100 - _PULLBACK_PROFIT_MULT_1 * Math.pow(1/_PEAK_PROFIT_IN_POSITIONS * 2000000,1/3)) /100;               // 计算回调止盈价格(利润百分比)
            _pullback_profit_price_2    = _PEAK_PROFIT_IN_POSITIONS * (100 - _PULLBACK_PROFIT_MULT_2 * Math.pow(1/_PEAK_PROFIT_IN_POSITIONS * 2000000,1/3)) / 100;              // 计算回调清仓价格(利润百分比)
            //_pullback_profit_price = _PEAK_PROFIT_IN_POSITIONS * (1 - _PULLBACK_PROFIT_PRICEPERCENT / 100);                                               // 计算回调的止盈价格(使用的是交易对价格回撤百分比)

            if (positions_profit_percent < _pullback_profit_price && _pullback_profit_hastakeprofit == false) {     // 达到回调止盈点位1,则部分减仓
                var amount  = _FixAmountPrecision(_order_size * _PULLBACK_PROFIT_AMOUNTPERCEHT / 100, _amount_precision);        // 止盈数量(下单量的百分比)
                Log("空 --> 利润回调第" + (_pullback_profit_repeattimes + 1) + "次减仓,数量: " + amount);
                Log(
                    "最高利润: ", _N(_PEAK_PROFIT_IN_POSITIONS , 2) + "%",
                    ", 当前利润: ", _N(positions_profit_percent, 2) + "%",
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _ReduceShort(-1,amount);                                // 空单减仓
                _CalculateProfit(positions, account, ticker);           // 统计收益
                //_PEAK_PROFIT_IN_POSITIONS           = _PEAK_PROFIT_IN_POSITIONS * (1 - Math.sqrt(_PULLBACK_PROFIT_PRICEPERCENT) / 100)   //峰值下降一点
                _PEAK_PROFIT_IN_POSITIONS           = _PEAK_PROFIT_IN_POSITIONS * 0.97;                                             // 止盈之后,利润峰值下降一点
                _pullback_profit_hastakeprofit      = true;                                                                         // 已经止盈过了
                _pullback_profit_repeattimes        += 1;                                                                           // 执行了一次止盈回调,次数+1
                _pullback_profit_switch             = false;                                                                        //  利润回调之后要关一下开关
                _pullback_profit_price              = 0;                                                                            // 重置利润回调止盈

                if(_pullback_profit_repeattimes >= _PULLBACK_PROFIT_MAXREPEATTIMES)
                {
                    Log("利润回调止盈次数已用尽。");          //次数用尽消息
                }
            }
        }

        // 回调清仓
        // 启用了回调止盈平仓,并且临时开关打开了,并且当前利润 < 平仓利润
        if (_PULLBACK_PROFIT_OPEN_2 &&_pullback_profit_switch_2 && positions_profit_percent < _pullback_profit_price_2) {// 达到回调止盈点位2,则完全平仓
                
                Log("空 --> 利润回调平仓,当前持仓全部清空。");
                Log(
                    "最高利润: ",   _N(_PEAK_PROFIT_IN_POSITIONS , 2) + "%",
                    ", 当前利润: ", _N(positions_profit_percent, 2) + "%",
                    ", 当前价格: ", _N(price, 6),
                    ", 持仓价格: ", _N(positions[0].Price, 6));          // 输出回调止盈信息

                _Cover_1();                                             // 快速平仓
                _ResetVariables();                                      // 重置运算变量
                _CalculateProfit(positions, account, ticker);           // 统计收益
            } 
    }
}






// 收益统计
function _CalculateProfit(positions, account, ticker) 
{
    // 重新获取一下账户持仓与资产
    var account_asset = _GetAccountAsset(positions, account, ticker)

    // 当前总收益 = 上一次总收益 + 本次的收益
    var current_profit = (account_asset - _init_asset) - _profit_local;  //本次收益

    _profit_local += current_profit; //总收益

    //// 检查重启后是否存在多单或空单
    if (current_profit > 0)
    {
        _take_profit_count++;
    }
    _trade_count++;

    LogProfit(_N(_profit_local, 4), "本次收益: ", _N(current_profit, 6),",  当前资金: ", _N(account_asset, 4));
    _SaveUserDatasLocal();
}


function main() 
{
    _trade_currency = _C(exchange.GetCurrency);         // 获取交易对信息
    

    Log("交易对: ",_trade_currency);

    _SetContract(_trade_currency);  // 设置合约
    
    positions       = _C(exchange.GetPositions);        // 获取仓位信息
    account         = _C(exchange.GetAccount);          // 获取账户信息
    ticker          = _C(exchange.GetTicker);           // 获取市场行情
    

    _InitDatas(positions, account, ticker);             // 初始化数据
    _Initialize(positions);                             // 重启后检查是否存在多单和空单

    while (true) 
    {
        

       ////////////////////////////消息监测//////////////////////////////////////////////////////////////////////////
        var command = GetCommand();                     // 监测消息

        if (command)
        {   // 如果有消息,则执行命令
            Log("接收到的命令: ", command, "#FF1CAE");
            if(command.indexOf("FMZ_") == 0)
            {
                _RunCommand(command);    //执行FMZ交互指令
            }
            else
            {
                try{
                    var TV_message   = JSON.parse(command);  //格式化消息,方便之后的处理
                    {
                        _RunTVCommand(TV_message);  //执行TradingView指令
                    }
                }
                catch(error)
                {
                    Log("JSON解析出现错误 : ", error);
                }
            }
        }
        
        ////////////////////////////消息监测//////////////////////////////////////////////////////////////////////////

        ///////////////////////////仓位监控///////////////////////////////////////////////////////////////////////////

        _PositionMonitoring();       // 仓位监控

        //////////////////////////////////////////////////////////////////////////////////////////////////////
        Sleep(_interval);           // 程序运行间隔
    }
}