A mensagem que saiu do relógio da TV foi: OpenLong mais OpenShort está em branco CloseLong é muito simples. CloseShort em branco
O nome do alerta pode ser preenchido como quiser e o conteúdo da mensagem deve ser em inglês (somente em inglês, sem espaços e outros símbolos). Lembre-se de preencher a URL correta do Webhook
Para mais informações:https://www.fmz.com/bbs-topic/5533
Explicação:
Receber um sinal de stop loss da TV, mas o sinal de TV é enviado após o término do K-bar, e o stop loss neste script é projetado para impedir que o soquete; O bloqueador pode ser um pouco maior do que o bloqueador da TV, cerca de 0,25 vezes (o que é um pequeno bloqueador de 0,75%).
////TradingView信号 ////从TradingView接收开仓、平仓信号(OpenLong/CloseLong,OpenShort/CloseShort)执行开仓、平仓操作。 ////记得填写正确的Webhook URL 参考地址:https://www.fmz.com/bbs-topic/5533 ////暂时只测试了U本位交易。 ////只能做一个多单,如果当前有多单,不再继续开多;同样的逻辑适用于空单; 0.1.0 ////将夏天不打你的代码融入进来 V 0.1.3 2023年4月29日 03:35:31 策略地址:https://www.fmz.com/strategy/320782(源代码已经不再维护) ////夏天不打你的微信:wd1061331106 ////V0.1.9//根据原来的0.1.4进行了修改,重启后可以更新止盈止损价格;2024年11月22日 15:38:45 ////如果遇到交易平台发送的Too many requests的消息,不会停机(非常棒)。 ////V0.1.10 修正了挂单止盈成交之后,收到平仓信息报错的问题。2024年11月22日 21:20:00 // 参数设置 // 策略参数变量 // 基本设置 var _Currency = TradeCurrency; // 交易对 var _Interval = Interval; // 程序运行周期 var _UseQuarter = UseQuarter; // 季度合约,默认USDT永续合约 var _EnableMessageSend = EnableMessageSend; // 推送消息 // 下单设置 var _MarginLevel = MarginLevel; // 杠杆倍数 var _OrderSize = OrderSize; // 下单数量/张数 var _OrderByMargin = OrderByMargin; // 根据下单保证金来确定下单数量 var _OrderMarginPercent = OrderMarginPercent; // 下单保证金百分比%(根据初始资金计算) var _PricePrecision = PricePrecision; // 下单价格精度 var _AmountPrecision = AmountPrecision; // 下单数量精度 var _OneSizeInCurrentCoin = OneSizeInCurrentCoin; // U本位合约中,一张ETH所代表的ETH数量 var _QuarterOneSizeValue = QuarterOneSizeValue; // 币本位合约中,一张ETH所代表的USDT数量 // 止盈止损 var _UseStopLoss = UseStopLoss; // 使用止损 var _TakeProfitPercent = TakeProfitPercent; // 止盈价格百分比% var _TakeProfitAmount = TakeProfitAmount; // 止盈数量百分比% var _TakeProfitPrice = 0; // 止盈价格,用于显示 var _StopLossPercent = StopLossPercent; // 止损价格百分比 var _UseTrackingTakeProfit = UseTrackingTakeProfit; // 使用回调止盈 var _CallBakcPercent = CallBakcPercent; // 回调百分比% var takeProfitOrderId; //记录止盈单1 var ALLPrice_zhicheng = 0; //记录支撑价格 // 统计变量 var _InitAsset = 0; var _ProfitLocal = 0; var _TakeProfitCount = 0; var _TradeCount = 0; var StrategyRunTimeStampString = "strategy_run_time"; var _StrategyDatas = { start_run_timestamp: 0, others: "" }; var _UserDatas = null; // 相对固定参数 var _MaintenanceMarginRate = 0.004 // 维持保证金率 var _TakerFee = 0.0005; // 吃单手续费 var _IsUsdtStandard = false; // USDT本位开单和结算 var stopLossPrice = 0; //用于记录支撑价格,方便进行止损操作; // 全局变量 var position; var baseMargin; var assetPrecision;//获取资产精度,并将其存储在全局变量中: var pricePrecision; // 在全局变量中添加一个新变量,用于存储价格精度 var DEFAULT_ASSET_PRECISION = 3; var DEFAULT_PRICE_PRECISION = 2; // 在这里添加价格精度的默认值 var hasOpenedLong = false; // 跟踪是否已经开过多单 var hasOpenedShort = false; // 跟踪是否已经开过空单 var _HasTakeProfit = false; //是否止盈过? var _TriggeredTakeProfit = false; // 是否触发了回调止盈 var _PeakPriceInPosition = 0; // 持仓中价格的峰值点(最高/最低点) var lock = false; //锁定止损价格一段时间,保证开仓之后不会因为TV上的止损价格未发生变化而导致的立刻平仓。 var lastUpdateTime = 0; //记录上次止损价格更新时间的变量 // 保存程序起始运行时间 秒级时间戳 function saveStrategyRunTime() { var local_data_strategy_run_time = _G(StrategyRunTimeStampString); if (local_data_strategy_run_time == null) { _StrategyDatas.start_run_timestamp = Unix(); _G(StrategyRunTimeStampString, _StrategyDatas.start_run_timestamp); } else { _StrategyDatas.start_run_timestamp = local_data_strategy_run_time; } } // 设置程序起始运行时间 秒级时间戳 function setStrategyRunTime(timestamp) { _G(StrategyRunTimeStampString, timestamp); _StrategyDatas.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() { _UserDatas = { init_assets: _InitAsset, profit_local: _ProfitLocal, take_profit_count: _TakeProfitCount, trade_count: _TradeCount }; // 存储到本地 _G(exchange.GetLabel(), _UserDatas); Log("已把所有数据保存到本地."); } // 读取用户本地数据,程序启动时候运行一次 function readUserDataLocal() { var user_data = _G(exchange.GetLabel()); if (user_data == null) { _InitAsset = getAccountAsset(_C(exchange.GetPosition), _C(exchange.GetAccount), _C(exchange.GetTicker)); _UserDatas = { init_assets: _InitAsset, profit_local: 0, take_profit_count: 0, trade_count: 0 }; } else { _UserDatas = user_data; } } // 清除用户本地数据,交互按钮点击运行 function clearUserDataLocal() { _G(exchange.GetLabel(), null); Log(exchange.GetLabel(), ":已清除本地数据."); } //将购买数量调整为合适的精度: function fixAmountPrecision(amount, _AmountPrecision) { return parseFloat(amount.toFixed(_AmountPrecision)); } // 添加一个新函数,用于将价格调整到合适的精度 function fixPricePrecision(price, _PricePrecision) { return parseFloat(price.toFixed(_PricePrecision)); } // 策略交互 function runCmd(cmd) { if (cmd) { // 检测交互命令 Log("接收到的命令:", cmd, "#FF1CAE"); if (cmd.indexOf("ClearLocalData:") == 0) { // 清除本地数据 clearUserDataLocal(); } else if (cmd.indexOf("SaveLocalData:") == 0) { // 保存数据到本地 saveUserDatasLocal(); } else if (cmd.indexOf("ClearLog:") == 0) { // 清除日志 var log_reserve = cmd.replace("ClearLog:", ""); LogReset(Number(log_reserve)); } else if (cmd.indexOf("OrderSize:") == 0) { // 修改下单张数 if (_OrderByMargin) { Log("已经使用保证金数量来下单,无法直接修改下单数量!"); } else { var order_size = Number(cmd.replace("OrderSize:", "")); _OrderSize = order_size; Log("下单张数已经修改为:", _OrderSize); } } else if (cmd.indexOf("OrderMarginPercent:") == 0) { // 修改下单保证金百分比 if (_OrderByMargin) { var order_margin_percent = Number(cmd.replace("OrderMarginPercent:", "")); _OrderMarginPercent = order_margin_percent; Log("下单保证金百分比:", _OrderMarginPercent, "%"); } else { Log("没有打开根据保证金数量下单,无法修改下单保证金百分比!"); } } } } //// 检查重启后是否存在多单或空单 function initialize() { // 检查重启后是否存在多单或空单 var positions = exchange.GetPosition(); for (var i = 0; i < positions.length; i++) { if (positions[i].Type === PD_LONG || positions[i].Type === PD_LONG_YD) { hasOpenedLong = true; stopLossPrice = positions[i].Price * (1 - _StopLossPercent / 100);//更新止损价格--多单 Log("存在多单,止损价格更新:",stopLossPrice); } else if (positions[i].Type === PD_SHORT || positions[i].Type === PD_SHORT_YD) { hasOpenedShort = true; stopLossPrice = positions[i].Price * (1 + _StopLossPercent / 100);//更新止损价格--空单//更新止损价格--空单 Log("存在空单,止损价格更新:",stopLossPrice); } } } // 交易函数 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("空单平仓:",price,"数量:",amount); } else { tradeFunc = exchange.Buy; Log("多单平仓:",price,"数量:",amount); } exchange.SetDirection(distance); return tradeFunc(price, amount); } function openLong(price, amount) { var real_amount = getRealOrderSize(price, amount); return orderDirectly("buy", price, real_amount); } function openShort(price, amount) { var real_amount = getRealOrderSize(price, amount); return orderDirectly("sell", price, real_amount); } function coverLong(price, amount) {//多单平仓 if (takeProfitOrderId) {// 取消止盈单 exchange.CancelOrder(takeProfitOrderId); Log("取消多单止盈单"); takeProfitOrderId = null; _TakeProfitPrice = 0; //更新止盈价格 } Sleep(200); return orderDirectly("closebuy", price, amount); } function coverShort(price, amount) {//平仓空单 if (takeProfitOrderId) {// 取消止盈单 exchange.CancelOrder(takeProfitOrderId); Log("取消空单止盈单"); takeProfitOrderId = null; _TakeProfitPrice = 0; //更新止盈价格 } Sleep(200); return orderDirectly("closesell", price, amount); } // 重新计算下单数量 function getRealOrderSize(price, amount) { var real_price = price == -1 ? _C(exchange.GetTicker).Last : price; if (_OrderByMargin) { if (_IsUsdtStandard) { _OrderSize = _N(_InitAsset * (_OrderMarginPercent / 100) / real_price * _MarginLevel / _OneSizeInCurrentCoin, _AmountPrecision); } else { _OrderSize = _N(_InitAsset * (_OrderMarginPercent / 100) * _MarginLevel * real_price / _QuarterOneSizeValue, _AmountPrecision); } } else { _OrderSize = amount; } return _OrderSize; } // 获取单向持仓的收益和收益% function getSinglePositionProfit(position, ticker) { if (position.length == 0) return [0, 0]; var price = ticker.Last; var position_margin = getSinglePositionMargin(position, ticker); var position_profit_percent = position[0].Type == PD_LONG ? ((price - position[0].Price) / position[0].Price) * _MarginLevel : ((position[0].Price - price) / position[0].Price) * _MarginLevel; var position_profit = position_margin * position_profit_percent; return [position_profit, position_profit_percent]; } // 计算强平价格 function calculateForcedPrice(account, position, ticker) { var position_profit = 0; var total_avail_balance = 0; var forced_price = 0; var position_margin = getSinglePositionMargin(position, ticker); [position_profit, position_profit_percent] = getSinglePositionProfit(position, ticker); if (_IsUsdtStandard) { total_avail_balance = position_profit > 0 ? account.Balance + position_margin + account.FrozenBalance - position_profit : account.Balance + position_margin + account.FrozenBalance; if (position[0].Type == PD_LONG) { forced_price = (((_MaintenanceMarginRate + _TakerFee) * _MarginLevel * account.FrozenBalance - total_avail_balance) / _OneSizeInCurrentCoin + (position[0].Amount * position[0].Price)) / (position[0].Amount - (_MaintenanceMarginRate + _TakerFee) * position[0].Amount); } else { forced_price = (((_MaintenanceMarginRate + _TakerFee) * _MarginLevel * account.FrozenBalance - total_avail_balance) / _OneSizeInCurrentCoin - (position[0].Amount * position[0].Price)) / (-1 * position[0].Amount - (_MaintenanceMarginRate + _TakerFee) * position[0].Amount); } } else { total_avail_balance = position_profit > 0 ? account.Stocks + position_margin + account.FrozenStocks - position_profit : account.Stocks + position_margin + account.FrozenStocks; if (position[0].Type == PD_LONG) { forced_price = (_MaintenanceMarginRate * position[0].Amount + position[0].Amount) / (total_avail_balance / _QuarterOneSizeValue + position[0].Amount / position[0].Price); } else { forced_price = (_MaintenanceMarginRate * position[0].Amount - position[0].Amount) / (total_avail_balance / _QuarterOneSizeValue - position[0].Amount / position[0].Price); } } if (forced_price < 0) forced_price = 0; return forced_price; } // 计算最大可下单张数 function getMaxOrderSize(margin_level, ticker, account) { var max_order_size = 0; if (_IsUsdtStandard) { max_order_size = account.Balance * margin_level / (_OneSizeInCurrentCoin * ticker.Last); } else { max_order_size = account.Stocks * ticker.Last / _QuarterOneSizeValue * margin_level; } return _N(max_order_size, _AmountPrecision); } // 获取单个持仓占用保证金 function getSinglePositionMargin(position, ticker) { var position_margin = 0; if (position.length > 0) { if (_IsUsdtStandard) { position_margin = position[0].Amount * _OneSizeInCurrentCoin * ticker.Last / _MarginLevel; } else { position_margin = position[0].Amount * _QuarterOneSizeValue / ticker.Last / _MarginLevel; } } return position_margin; } // 获取账户资产 function getAccountAsset(position, account, ticker) { // 计算不同情况下的账户初始资产 var account_asset = 0; var position_margin = getSinglePositionMargin(position, ticker); if (_IsUsdtStandard) { if (position.length > 0) { account_asset = account.Balance + account.FrozenBalance + position_margin; } else { account_asset = account.Balance + account.FrozenBalance; } } else { if (position.length > 0) { account_asset = account.Stocks + account.FrozenStocks + position_margin; } else { account_asset = account.Stocks + account.FrozenStocks; } } return account_asset; } // 收益统计 function calculateProfit(ticker) { // 重新获取一下账户持仓与资产 var position = _C(exchange.GetPosition); var account = _C(exchange.GetAccount); // 当前总收益 - 上一次总收益 = 本次的收益 var current_profit = (getAccountAsset(position, account, ticker) - _InitAsset) - _ProfitLocal; _ProfitLocal += current_profit; if (current_profit > 0) { _TakeProfitCount++; } _TradeCount++; LogProfit(_N(_ProfitLocal, 4), " 本次收益:", _N(current_profit, 6)); Log(getAccountAsset(position, account, ticker), 4), " 当前资金:", _N(getAccountAsset(position, account, ticker), 6); saveUserDatasLocal(); } // 是否还够资金下单 function isEnoughAssetToOrder(order_size, ticker) { var is_enough = true; var account = _C(exchange.GetAccount); if (_IsUsdtStandard) { if (account.Balance < order_size * ticker.Last * _OneSizeInCurrentCoin / _MarginLevel) { is_enough = false; } } else { if (account.Stocks < order_size * _QuarterOneSizeValue / ticker.Last / _MarginLevel) { is_enough = false; } } return is_enough; } // 止损--------------------- function stopLoss(stopLossPrice, position, ticker) { var stop_loss_price = 0; var price = ticker.Last; if (position.length == 1 && _UseStopLoss) { if (position[0].Type == PD_LONG) { stop_loss_price = stopLossPrice; //设定止损价格 if (price < stop_loss_price) { coverLong(-1, position[0].Amount); _HasTakeProfit = false; calculateProfit(ticker); //统计收益 _TrendWhenTakeProfitOrStopLoss = 1; _HadStopLoss = true; Log("多单止损。止损价格:", _N(stop_loss_price, 6), ", 持仓价格:", _N(position[0].Price), _EnableMessageSend ? "@" : "#FF1CAE"); } } else if (position[0].Type == PD_SHORT) { stop_loss_price = stopLossPrice; //设定止损价格 if (price > stop_loss_price) { coverShort(-1, position[0].Amount); _HasTakeProfit = false; calculateProfit(ticker); //统计收益 _TrendWhenTakeProfitOrStopLoss = -1; _HadStopLoss = true; Log("空单止损。止损价格:", _N(stop_loss_price, 6), ", 持仓价格:", _N(position[0].Price), _EnableMessageSend ? "@" : "#FF1CAE"); } } } } // 止盈 function takeProfit(position, ticker) { var take_profit_price = 0; var price = ticker.Last; if (position.length == 1) { if (position[0].Type == PD_LONG) { take_profit_price = position[0].Price * (1 + _TakeProfitPercent / 100); //设定止盈价格 _TakeProfitPrice = take_profit_price; //记录止盈价格 if (price > take_profit_price) { var takeProfitAmount = fixAmountPrecision(position[0].Amount * _TakeProfitAmount / 100, _AmountPrecision); // 调整数量精度 //coverLong(-1, takeProfitAmount); _HasTakeProfit = true; calculateProfit(ticker); //统计收益 _TrendWhenTakeProfitOrStopLoss = 1; _HadTakeProfit = true; Log("多单止盈。止盈价格:", _N(take_profit_price, 6), ", 持仓价格:", _N(position[0].Price), _EnableMessageSend ? "@" : "#FF1CAE"); _TriggeredTakeProfit = true; //打开回调止盈开关 _PeakPriceInPosition = price; // 记录价格高点 takeProfitOrderId = null; } } else if (position[0].Type == PD_SHORT) { take_profit_price = position[0].Price * (1 - _TakeProfitPercent / 100); _TakeProfitPrice = take_profit_price; //记录止盈价格 if (price < take_profit_price) { var takeProfitAmount = fixAmountPrecision(position[0].Amount * _TakeProfitAmount / 100, _AmountPrecision); // 调整数量精度 //coverShort(-1, takeProfitAmount); _HasTakeProfit = true; calculateProfit(ticker); //统计收益 _TrendWhenTakeProfitOrStopLoss = -1; _HadTakeProfit = true; Log("空单止盈。止盈价格:", _N(take_profit_price, 6), ", 持仓价格:", _N(position[0].Price), _EnableMessageSend ? "@" : "#FF1CAE"); _TriggeredTakeProfit = true; //回调止盈开关打开 _PeakPriceInPosition = price; // 记录价格高点 takeProfitOrderId = null; } } } } // 回调止盈 function trackingTakeProfit(position, ticker) { var take_profit_price = 0; var trigger_price = 0; var price = ticker.Last; if (position.length > 0 && _UseTrackingTakeProfit) { if (position[0].Type == PD_LONG) { // 多单持仓 if (price > position[0].Price * (1 - _CallBakcPercent / 100)) {_TriggeredTakeProfit = true;} if (_TriggeredTakeProfit) {// 止盈回调代码(开关开启,监控是否止盈) _PeakPriceInPosition = price > _PeakPriceInPosition ? price : _PeakPriceInPosition; // 更新价格高点 take_profit_price = _PeakPriceInPosition * (1 - _CallBakcPercent / 100); // 计算回调的止盈价格 if (price < take_profit_price) {//如果价格低于回调止盈价格,则止盈 coverLong(-1, position[0].Amount); // 平多 _HasTakeProfit = false; calculateProfit(ticker); //统计收益 _TriggeredTakeProfit = false; // 复位触发标记 _HadTakeProfit = true; // 记录发生了止盈 Log("多单回调止盈:持仓中价格高点:", _N(_PeakPriceInPosition, 6), ", 止盈价格:", _N(take_profit_price, 6), ", 当前价格:", _N(price, 6), ", 持仓价格:", _N(position[0].Price, 6), _EnableMessageSend ? "@" : "#FF1CAE"); } } } else if (position[0].Type == PD_SHORT) { // 空单持仓 if (price < position[0].Price * (1 + _CallBakcPercent / 100)) {_TriggeredTakeProfit = true;} if (_TriggeredTakeProfit) { // 已达到触发价格,监控是否止盈 _PeakPriceInPosition = price < _PeakPriceInPosition ? price : _PeakPriceInPosition; // 更新价格低点 take_profit_price = _PeakPriceInPosition * (1 + _CallBakcPercent / 100); // 计算回调的止盈价格 if (price > take_profit_price) { coverShort(-1, position[0].Amount); // 平空 _HasTakeProfit = false; calculateProfit(ticker); //统计收益 _TriggeredTakeProfit = false; // 复位触发标记 _HadTakeProfit = true; // 记录发生了止盈 Log("空单回调止盈:持仓中价格低点:", _N(_PeakPriceInPosition, 6), ", 止盈价格:", _N(take_profit_price, 6), ", 当前价格:", _N(price, 6), ", 持仓价格:", _N(position[0].Price, 6), _EnableMessageSend ? "@" : "#FF1CAE"); } } } } } // 下单 function order(long, short, position, ticker) { var position_size = position.length > 0 ? position[0].Amount : 0; var position_type = position.length > 0 ? position[0].Type : null; if (long) { //判断是否持仓 if (position_size > 0 && position_type == PD_SHORT) { //如果当前持有空仓 coverShort(-1, position_size); //平掉空仓 calculateProfit(ticker); //统计收益 } else if (position_size > 0 && position_type == PD_LONG) { //如果当前持有多仓 Log("持有多单,不继续开多"); // 多单持仓,不重复下单 return; } else { } ////开多单 if (isEnoughAssetToOrder(_OrderSize, ticker)) { // 是否还够资金下单 openLong(-1, _OrderSize); //开多单 _HadStopLoss = false; //重置 _HadTakeProfit = false; //重置 lastUpdateTime = new Date().getTime(); //开单平单之后,更新时间 Sleep(500); // 挂多单止盈单 try { var takeProfitPrice = ticker.Buy * (1 + _TakeProfitPercent / 100); //设定止盈价格 takeProfitPrice = fixPricePrecision(takeProfitPrice, _PricePrecision); //调整价格精度 var takeProfitAmount = _OrderSize * _TakeProfitAmount / 100; //设定止盈数量 takeProfitAmount = fixAmountPrecision(takeProfitAmount, _AmountPrecision); //调整数量精度 _TakeProfitPrice = takeProfitPrice; //更新止盈价格--多单 stopLossPrice = ticker.Buy * (1 - _StopLossPercent / 100);//更新止损价格--多单 Log("开仓价格:",ticker.Buy,"止损价格:", stopLossPrice); //输出开仓价格,止损价格 exchange.SetDirection("closebuy"); // 设置止盈平多交易方向 takeProfitOrderId = exchange.Sell(takeProfitPrice, takeProfitAmount); //挂止盈单 Log("挂多单止盈单,价格:", takeProfitPrice, ",数量:", takeProfitAmount); //输出日志 } catch (error) { Log("挂多单止盈单失败:", error.message, "错误详情:", error); takeProfitOrderId = null; } } else { throw "保证金不足!"; } } else if (short) { ////判断是否持仓 if (position_size > 0 && position_type == PD_LONG) { //如果当前持有多仓 coverLong(-1, position_size); //平掉多仓 calculateProfit(ticker); //统计收益 } else if (position_size > 0 && position_type == PD_SHORT) { Log("持有空单,不继续开空"); // 多单持仓,不重复下单// 空单持仓,不重复下单 return; } else { } ////开空单 if (isEnoughAssetToOrder(_OrderSize, ticker)) { openShort(-1, _OrderSize); //开空单 _HadStopLoss = false; //重置 _HadTakeProfit = false; //重置 lastUpdateTime = new Date().getTime(); //开单平单之后,更新时间 Sleep(500); // 挂空单止盈单 try { var takeProfitPrice = ticker.Sell * (1 - _TakeProfitPercent / 100); //设定止盈数量 takeProfitPrice = fixPricePrecision( takeProfitPrice , _PricePrecision); //调整价格精度 var takeProfitAmount = _OrderSize * _TakeProfitAmount/100; //设定止盈数量 takeProfitAmount = fixAmountPrecision(takeProfitAmount, _AmountPrecision ); //调整数量精度 _TakeProfitPrice = takeProfitPrice; //更新止盈价格--空单 stopLossPrice = ticker.Sell * (1 + _StopLossPercent / 100); //更新止损价格--空单 Log("开仓价格:",ticker.Sell,"止损价格:", stopLossPrice); //输出开仓价格,止损价格 exchange.SetDirection("closesell"); //设置止盈平多交易方向 takeProfitOrderId = exchange.Buy(takeProfitPrice, takeProfitAmount); //挂止盈单 Log("挂空单止盈单,价格:", takeProfitPrice, ",数量:", takeProfitAmount); //输出日志 } catch (error) { Log("挂空单止盈单失败:", error.message, "错误详情:", error); takeProfitOrderId = null; } } else { throw "保证金不足!"; } } } // 状态栏信息打印 function printLogStatus(ticker, account, position) { 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 i = 0; // 策略总览 var the_running_days = getDaysFromTimeStamp(_StrategyDatas.start_run_timestamp, Unix()); var monthly_rate_of_profit = 0; if (the_running_days > 1) monthly_rate_of_profit = _ProfitLocal / _InitAsset / the_running_days * 30; table_overview.rows.push([ _D(_StrategyDatas.start_run_timestamp * 1000), //开始时间 the_running_days, //已运行天数 _TradeCount, //交易次数 _TradeCount == 0 ? 0 : (_N(_TakeProfitCount / _TradeCount * 100, 2) + "%"), //胜率 _N(monthly_rate_of_profit * 100, 2) + "%", //预估月化% _N(monthly_rate_of_profit * 12 * 100, 2) + "%", //预估年化% '地址:https://www.fmz.com/strategy/320782,作者微信:wd1061331106' //策略代谢请联系微信 ]); // 账户资金 var current_asset = getAccountAsset(position, account, ticker); var max_order_size = getMaxOrderSize(_MarginLevel, ticker, account); var asset_profit = current_asset - _InitAsset; var asset_profit_percent = asset_profit / _InitAsset; table_account.rows.push([ _N(current_asset, 4), //当前资产 _N(_InitAsset, 4), //初始资产 _N(_IsUsdtStandard ? account.Balance : account.Stocks, 4), //可用余额 _N(_IsUsdtStandard ? account.FrozenBalance : account.FrozenStocks, 4), //冻结余额 max_order_size, //可下单张数 _N(asset_profit, 4), //收益 _N(asset_profit_percent * 100, 2) + "%" //收益百分比 ]); // 持仓情况 var position_direction = ""; var forced_cover_up_price = 0; var position_profit_percent = 0; var position_profit = 0; var position_margin = 0; if (position.length == 0) { table_position.rows.push(["无持仓", "-", "-", "-", "-", "-", "-", "-", "-"]); } else { position_direction = position[0].Type == PD_LONG ? "多单" : "空单"; [position_profit, position_profit_percent] = getSinglePositionProfit(position, ticker); position_margin = getSinglePositionMargin(position, ticker); //forced_cover_up_price = calculateForcedPrice(account, position, ticker); table_position.rows.push([ exchange.GetCurrency(), //交易币种 _MarginLevel, //杠杆倍数 _N(position[0].Price, 4), //持仓均价 position_direction, //方向 position[0].Amount, //数量 _N(position_margin, 4), //保证金 _N(stopLossPrice, 4), //止损价格 _N(_TakeProfitPrice, 4), //止盈价格 _N(position_profit, 4), //浮动盈亏 _N((position_profit_percent * 100), 2) + "%" //浮动盈亏百分比 ]); } // 打印表格 LogStatus('`' + JSON.stringify(table_overview) + '`\n' + '`' + JSON.stringify(table_account) + '`\n' + '`' + JSON.stringify(table_position) + '`\n'); } // 初始化数据 function initDatas() { saveStrategyRunTime(); readUserDataLocal(); _InitAsset = _UserDatas.init_assets; _ProfitLocal = _UserDatas.profit_local; _TakeProfitCount = _UserDatas.take_profit_count; _TradeCount = _UserDatas.trade_count; if (_OrderByMargin) { getRealOrderSize(-1, _OrderSize); Log("已经重新计算下单张数:", _OrderSize); } } // 设置合约 function setContract() { _IsUsdtStandard = _Currency.includes("USDT") ? true : false; if (!IsVirtual()) { // 实盘设置 exchange.SetCurrency(_Currency); if (_UseQuarter) { exchange.SetContractType("quarter"); } else { exchange.SetContractType("swap"); } } else { // 回测设置 if (_IsUsdtStandard) { exchange.SetContractType("swap"); } else { exchange.SetContractType("quarter"); } } exchange.SetMarginLevel(_MarginLevel); exchange.SetPrecision(_PricePrecision, _AmountPrecision); } function main() { setContract(); // 设置合约 initDatas(); // 初始化数据 initialize();//检查是否存在多单和空单 while (true) { var command = GetCommand(); //获取WebHook消息 if (command) { // 检查 command 是否为空 Log("接收到的命令:", command, "#FF1CAE"); TV_FMZ_Strategy(command); //开单平单操作 } Take_Profit_Stop_Loss(); //止盈止损操作 Sleep(_Interval); // 程序运行间隔 } } //止盈止损函数 function Take_Profit_Stop_Loss(){ var ticker = _C(exchange.GetTicker); //获取当前交易对的市场行情信息 var account = _C(exchange.GetAccount); //获取交易账户信息的函数。 var position = _C(exchange.GetPosition); //获取当前交易所账户的持仓信息,并返回一个包含持仓信息的对象。 printLogStatus(ticker, account, position); // 状态栏信息打印 if (stopLossPrice > 0) { //止损处理 stopLoss(stopLossPrice, position, ticker); // 止损 } if(!_HasTakeProfit){ takeProfit(position, ticker); // 止盈 } if (_TriggeredTakeProfit) { trackingTakeProfit(position, ticker); // 回调止盈 } } // 执行对应的操作 function TV_FMZ_Strategy(action) { var ticker = _C(exchange.GetTicker); //获取当前交易对的市场行情信息 var account = _C(exchange.GetAccount); //获取交易账户信息的函数。 var position = _C(exchange.GetPosition); //获取当前交易所账户的持仓信息,并返回一个包含持仓信息的对象。 if (position.length > 1) { ////如果同时持有多空仓位则退出 Log(position); throw "同时有多空持仓!"; } switch (action) { // 处理消息对应的操作 case "OpenLong": order(1, 0, position, ticker); // 开多单 break; case "OpenShort": order(0, 1, position, ticker); // 开空单 break; case "CloseLong": if (position.length > 0) { if (position[0].Type === PD_LONG) { coverLong(-1, position[0].Amount); // 平多 _HasTakeProfit = false; _TriggeredTakeProfit = false; // 复位回调止盈开关 calculateProfit(ticker); //统计收益 } else { Log("当前持有空头持仓,无法平多"); } } else { Log("没有持仓,无法平多"); } break; case "CloseShort": if (position.length > 0) { if (position[0].Type === PD_SHORT) { coverShort(-1, position[0].Amount); // 平空 _HasTakeProfit = false; _TriggeredTakeProfit = false; // 复位回调止盈开关 calculateProfit(ticker); //统计收益 } else { Log("当前持有多头持仓,无法平空"); } } else { Log("没有持仓,无法平空"); } break; default: break; } }
FeijãoA demonstração do disco real foi feita em: https://www.fmz.com/robot/591982