快捷手动交易工具箱:持仓和挂单操控·进阶篇
📘

快捷手动交易工具箱:持仓和挂单操控·进阶篇

第 2/3 篇

「面板初始化与按钮工厂函数」

在 MT5 自建交易面板时,窗口与控件的创建顺序直接决定后续交互是否生效。先调 m_main_window.CreateWindow 拿到主窗口句柄,若返回 false 必须立即 return,否则后面挂按钮会全部失效。 紧接着 CreateTabs(5,22+27) 建出 5 个标签页,纵向偏移 49 像素(22+27),这一步失败同样要中断。随后连续 5 次 CreateButton 把市价单、挂单、平仓类按钮铺到坐标 (20,10)、(210,10)、(20,60)、(20,110)、(210,60),其中市价相关用 C'87,128,255' 蓝、挂单类用 C'31,209,111' 绿做视觉区分。 CreateModeButton 是统一的按钮工厂:固定尺寸 80×20、字号 9、深紫底白字、悬停与按下不变色,仅接收 x_gap/y_gap 决定位置。注意它先把 button.MainPointer(m_tab) 指向当前 tab,再 m_tab.AddToElementsArray(0,button) 挂进元素数组——漏掉这步按钮不会随标签页切换显示。 CreateModeEdit 的入口注释显示它同样先存窗口指针,逻辑与按钮工厂对称,只是对象换成 CTextEdit。开 MT5 把这套坐标和颜色抄进自己的 EA 面板,能省掉反复调布局的功夫。外汇与贵金属杠杆高,面板只是下单辅助,不代表任何胜率保证。

MQL5 / C++
if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y))
   class="kw">return(class="kw">false);
class=class="str">"cmt">//--- Tabs
if(!CreateTabs(class="num">5,class="num">22+class="num">27))
   class="kw">return(class="kw">false);
class=class="str">"cmt">//---
if(!CreateButton(m_order_button[class="num">0],MARKET_ORDER_NAME+"(M)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">20,class="num">10))
   class="kw">return(class="kw">false);
if(!CreateButton(m_order_button[class="num">1],PENDING_ORDER_NAME+"(P)",C&class="macro">#x27;class="num">31,class="num">209,class="num">111&class="macro">#x27;,class="num">210,class="num">10))
   class="kw">return(class="kw">false);
if(!CreateButton(m_order_button[class="num">2],MARKET_ORDERS_PROFIT_CLOSE+"(C)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">20,class="num">60))
   class="kw">return(class="kw">false);
if(!CreateButton(m_order_button[class="num">3],MARKET_ORDERS_LOSS_CLOSE+"(D)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">20,class="num">110))
   class="kw">return(class="kw">false);
if(!CreateButton(m_order_button[class="num">4],PEND_ORDERS_ALL_CLOSE+"(R)",C&class="macro">#x27;class="num">31,class="num">209,class="num">111&class="macro">#x27;,class="num">210,class="num">60))
   class="kw">return(class="kw">false);
class=class="str">"cmt">//---
class="kw">return(true);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CFastTrading::CreateModeButton(CButton &button,class="type">class="kw">string text,class="type">int x_gap,class="type">int y_gap)
{
class=class="str">"cmt">//--- Store the window pointer
   button.MainPointer(m_tab);
class=class="str">"cmt">//--- Attach to tab
   m_tab.AddToElementsArray(class="num">0,button);
   class="type">class="kw">color baseclr=clrDarkViolet;
class=class="str">"cmt">//--- Set properties before creation
   button.XSize(class="num">80);
   button.YSize(class="num">20);
   button.Font(m_base_font);
   button.FontSize(class="num">9);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(baseclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(baseclr);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
class=class="str">"cmt">//--- Create a control element
   if(!button.CreateButton(text,x_gap,y_gap))
      class="kw">return(class="kw">false);
class=class="str">"cmt">//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(class="num">0,button);
   class="kw">return(true);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CFastTrading::CreateModeEdit(CTextEdit &text_edit,class="type">int x_gap,class="type">int y_gap)
{
class=class="str">"cmt">//--- Store the window pointer

◍ 挂单面板的输入框与窗口初始化

在 MT5 自定义面板里,数值输入框(CTextEdit)要先挂到标签页元素数组才能参与事件循环。下面这段把 text_edit 绑到 m_tab 的第 0 组,并设了 80×20 的像素尺寸、2 位小数、步进 0.01、区间 [0.01, 99999],同时开了 SpinEditMode 让交易者能直接滚轮调手数。 text_edit.SetValue(string(0.01)) 把初值锁成 0.01 手,随后 IsLocked(true) 禁止手动改——这种写法适合做“默认手数不可误触”的快单界面。注意 GetTextBoxPointer().XGap(1) 只调了文本区左边距,框体 XSize 仍是 80,渲染时不会错位。 CreateMainWindow 则搭了 600×375 的主窗,标题栏高 22、可拖动,背景与标题色用成员变量统一接管。它先建窗,再在 (5,20) 偏移上调用 CreateTabs(5,49) 生成标签页,然后以 45 像素为行距铺了 5 个下单按钮:市价单蓝、挂单绿、平仓类分别落在 x=10 与 x=300 两列。外汇与贵金属波动剧烈,这类一键面板若误触可能瞬间成交,实盘前务必在策略测试器里先验证坐标与锁定逻辑。 把下面代码直接塞进你的 CWndContainer 派生类,编译后开 MT5 附加到图表,就能看到可拖动的快单窗体原型。

MQL5 / C++
  text_edit.MainPointer(m_tab);
class=class="str">"cmt">//--- Attach to tab
  m_tab.AddToElementsArray(class="num">0,text_edit);
class=class="str">"cmt">//--- Properties
  text_edit.XSize(class="num">80);
  text_edit.YSize(class="num">20);
  text_edit.Font(m_base_font);
  text_edit.FontSize(m_base_font_size);
  text_edit.SetDigits(class="num">2);
  text_edit.MaxValue(class="num">99999);
  text_edit.StepValue(class="num">0.01);
  text_edit.MinValue(class="num">0.01);
  text_edit.SpinEditMode(true);
  text_edit.GetTextBoxPointer().XGap(class="num">1);
  text_edit.GetTextBoxPointer().XSize(class="num">80);
class=class="str">"cmt">//--- Create a control element
  if(!text_edit.CreateTextEdit("",x_gap,y_gap))
     class="kw">return(class="kw">false);
  text_edit.SetValue(class="type">class="kw">string(class="num">0.01));
  text_edit.IsLocked(true);
class=class="str">"cmt">//--- Add the object to the common array of object groups
  CWndContainer::AddToElementsArray(class="num">0,text_edit);
  class="kw">return(true);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Creates a form for orders                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CFastTrading::CreateMainWindow(class="type">void)
{
class=class="str">"cmt">//--- Add a window pointer to the window array
  CWndContainer::AddWindow(m_main_window);
class=class="str">"cmt">//--- Properties
  m_main_window.XSize(class="num">600);
  m_main_window.YSize(class="num">375);
class=class="str">"cmt">//--- Coordinates
  class="type">int x=class="num">5;
  class="type">int y=class="num">20;
  m_main_window.CaptionHeight(class="num">22);
  m_main_window.IsMovable(true);
  m_main_window.CaptionColor(m_caption_color);
  m_main_window.CaptionColorLocked(m_caption_color);
  m_main_window.CaptionColorHover(m_caption_color);
  m_main_window.BackColor(m_background_color);
  m_main_window.FontSize(m_base_font_size);
  m_main_window.Font(m_base_font);
class=class="str">"cmt">//--- Create the form
  if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y))
     class="kw">return(class="kw">false);
class=class="str">"cmt">//--- Tabs
  if(!CreateTabs(class="num">5,class="num">22+class="num">27))
     class="kw">return(class="kw">false);
class=class="str">"cmt">//---
  if(!CreateButton(m_order_button[class="num">0],MARKET_ORDER_NAME+"(M)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10))
     class="kw">return(class="kw">false);
  if(!CreateButton(m_order_button[class="num">1],PENDING_ORDER_NAME+"(P)",C&class="macro">#x27;class="num">31,class="num">209,class="num">111&class="macro">#x27;,class="num">300,class="num">10))
     class="kw">return(class="kw">false);
  if(!CreateButton(m_order_button[class="num">2],CLOSE_ALL_PROFIT+"(C)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">1))
     class="kw">return(class="kw">false);
  if(!CreateButton(m_order_button[class="num">3],PEND_ORDERS_ALL_CLOSE+"(R)",C&class="macro">#x27;class="num">31,class="num">209,class="num">111&class="macro">#x27;,class="num">300,class="num">10+class="num">45*class="num">1))
     class="kw">return(class="kw">false);
  if(!CreateButton(m_order_button[class="num">4],CLOSE_BUY_PROFIT,C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">2))
     class="kw">return(class="kw">false);

平仓按钮与模式切换的界面布局逻辑

这段面板初始化代码把「按盈亏平仓」的按钮排成了纵向队列:索引 5 到 8 分别对应平盈利多单、平盈利空单(带 D 后缀的平所有亏损单)、平亏损多单、平亏损空单,Y 坐标用 10+45*N 算出来,按钮高度间距固定 45 像素,配色统一走 C'87,128,255'(一种蓝)。 紧接着的 for 循环只跑 6 次,给 m_mode_buttonm_mode_edit 铺面板:按钮 X 在 195(205-10),编辑框 X 在 194(204-10),Y 随 i+1 步进 45。也就是说模式区最多挂 6 行,超了就不画——想加第 7 种过滤条件得先改循环上限。 底下那组 #define 把六种平仓语义做成英俄双语宏,运行时靠 m_language==RUSSIAN 切标签。你在 MT5 里接这套,若只做英文环境可直接删掉三元判断,省一点字符串开销。 ModeButtonSwitch 的开头用 lparam==button.Id() 做事件源过滤,再取 states 数组长度做轮询,比对 LabelText() 决定高亮态。外汇与贵金属杠杆高,这类一键平仓面板误触可能造成快速回撤,实盘前务必在策略测试器里用历史 tick 验证按钮响应。

MQL5 / C++
  if(!CreateButton(m_order_button[class="num">5],CLOSE_SELL_PROFIT,C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">3))
      class="kw">return(class="kw">false);
   if(!CreateButton(m_order_button[class="num">6],CLOSE_ALL_LOSS+"(D)",C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">4))
      class="kw">return(class="kw">false);
   if(!CreateButton(m_order_button[class="num">7],CLOSE_BUY_LOSS,C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">5))
      class="kw">return(class="kw">false);
   if(!CreateButton(m_order_button[class="num">8],CLOSE_SELL_LOSS,C&class="macro">#x27;class="num">87,class="num">128,class="num">255&class="macro">#x27;,class="num">10,class="num">10+class="num">45*class="num">6))
      class="kw">return(class="kw">false);
class=class="str">"cmt">//---
   for(class="type">int i=class="num">0; i<class="num">6; i++)
   {
      if(!CreateModeButton(m_mode_button[i],"all",class="num">205-class="num">10,class="num">10+class="num">45*(i+class="num">1)))
         class="kw">return(class="kw">false);
      if(!CreateModeEdit(m_mode_edit[i],class="num">204-class="num">10,class="num">30+class="num">45*(i+class="num">1)))
         class="kw">return(class="kw">false);
   }
class=class="str">"cmt">//---
   class="kw">return(true);
}
class="macro">#define CLOSE_BUY_PROFIT(m_language==RUSSIAN ? "Закрыть BUY прибыльные" : "Close BUY Profit")
class="macro">#define CLOSE_SELL_PROFIT(m_language==RUSSIAN ? "Закрыть SELL прибыльные" : "Close SELL Profit")
class="macro">#define CLOSE_ALL_PROFIT(m_language==RUSSIAN ? "Закрыть ВСЕ прибыльные" : "Close ALL Profit")
class="macro">#define CLOSE_BUY_LOSS(m_language==RUSSIAN ? "Закрыть BUY убыточные" : "Close BUY Losing")
class="macro">#define CLOSE_SELL_LOSS(m_language==RUSSIAN ? "Закрыть SELL убыточные" : "Close SELL Losing")
class="macro">#define CLOSE_ALL_LOSS(m_language==RUSSIAN ? "Закрыть ВСЕ убыточные" : "Close ALL Losing")
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CFastTrading::ModeButtonSwitch(CButton &button,class="type">long lparam,class="type">class="kw">string &states[])
{
   if(lparam==button.Id())
   {
      class="type">int size=ArraySize(states);
      for(class="type">int i=class="num">0; i<size; i++)
      {
         if(button.LabelText()==states[i])
         {

「按钮切换时编辑框的参数联动」

在自建快速交易面板里,按钮标签文字直接决定编辑框的数值类型。上面这段逻辑遍历 6 个模式按钮,一旦命中 lparam 对应的控件,就按 states 数组里的标签切换编辑框属性。 当标签等于 states[1] 时,编辑框解锁、整数位 0、步进 1、范围 1~9999,并强制写入字符串 "20",同时标记 m_current_mode[i]=1。若标签是 states[2],则改成两位小数、步进 0.01、下限 0.01 上限 99999,默认填 "0.1",模式记为 2——这是给点数或手数微调用的。 states[3] 分支又回到整数配置,和 states[1] 几乎一致只是模式值置 3。开 MT5 把这段塞进 CFastTrading::ModeEditSwitch,改 states 文本就能验证编辑框位数和步进是否跟着跳。外汇与贵金属波动剧烈,面板参数误设可能导致下单量异常,实盘前务必在策略测试器跑一遍。

MQL5 / C++
if(i==size-class="num">1)
      {
         SetButtonParam(button,states[class="num">0]);
         class="kw">break;
      }
      else
      {
         SetButtonParam(button,states[i+class="num">1]);
         class="kw">break;
      }
     }
   }
 }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CFastTrading::ModeEditSwitch(class="type">long lparam,class="type">class="kw">string &states[])
{
   for(class="type">int i=class="num">0; i<class="num">6; i++)
   {
      if(lparam==m_mode_button[i].Id())
      {
         if(m_mode_button[i].LabelText()==states[class="num">1])
         {
            m_mode_edit[i].IsLocked(class="kw">false);
            m_mode_edit[i].SetDigits(class="num">0);
            m_mode_edit[i].StepValue(class="num">1);
            m_mode_edit[i].MaxValue(class="num">9999);
            m_mode_edit[i].MinValue(class="num">1);
            m_mode_edit[i].SetValue(class="type">class="kw">string(class="num">20));
            m_mode_edit[i].GetTextBoxPointer().Update(true);
            m_current_mode[i]=class="num">1;
         }
         else if(m_mode_button[i].LabelText()==states[class="num">2])
         {
            m_mode_edit[i].IsLocked(class="kw">false);
            m_mode_edit[i].SetDigits(class="num">2);
            m_mode_edit[i].StepValue(class="num">0.01);
            m_mode_edit[i].MaxValue(class="num">99999);
            m_mode_edit[i].MinValue(class="num">0.01);
            m_mode_edit[i].SetValue(class="type">class="kw">string(class="num">0.1));
            m_mode_edit[i].GetTextBoxPointer().Update(true);
            m_current_mode[i]=class="num">2;
         }
         else if(m_mode_button[i].LabelText()==states[class="num">3])
         {
            m_mode_edit[i].IsLocked(class="kw">false);
            m_mode_edit[i].SetDigits(class="num">0);
            m_mode_edit[i].StepValue(class="num">1);
            m_mode_edit[i].MaxValue(class="num">9999);
            m_mode_edit[i].MinValue(class="num">1);
            m_mode_edit[i].SetValue(class="type">class="kw">string(class="num">20));

◍ 平仓面板的盈利模式分支与一键清仓

这段逻辑里,模式 4(sum>points)和模式 5(sum>currency)走的是汇总判断分支:当 m_current_mode[0] > 2 时,才进入持仓循环累加 sum_pp 与 sum_cur,否则单笔条件分支直接生效。 按钮切换时若标签等于 states[4](即 "sum>currency"),编辑框会被解锁、精度设为 2 位、步进 0.01、上下限 0.01~99999,并预填 0.1,m_current_mode[i] 记为 4;若匹配不到任何已知标签,编辑框锁死且模式归 0。 CloseAllMarketProfit 绑定了图元点击(m_order_button[2])和键盘 C 键两条触发路径。函数内先取 PositionsTotal() 得到当前持仓数,再按模式决定是否累计盈亏;外汇与贵金属杠杆高,一键全平可能触发滑点或断崖式净值波动,实盘前务必在策略测试器用历史数据跑通。 让小布替你跑这套 把 ModeEditSwitch 里的 states 数组和 m_current_mode 打印到 Experts 日志,切五次按钮看 m_current_mode 是否按 3/4/0 跳变,能省掉一半界面联调时间。

MQL5 / C++
m_mode_edit[i].GetTextBoxPointer().Update(true);
m_current_mode[i]=class="num">3;
 }
 else if(m_mode_button[i].LabelText()==states[class="num">4])
 {
 m_mode_edit[i].IsLocked(class="kw">false);
 m_mode_edit[i].SetDigits(class="num">2);
 m_mode_edit[i].StepValue(class="num">0.01);
 m_mode_edit[i].MaxValue(class="num">99999);
 m_mode_edit[i].MinValue(class="num">0.01);
 m_mode_edit[i].SetValue(class="type">class="kw">string(class="num">0.1));
 m_mode_edit[i].GetTextBoxPointer().Update(true);
 m_current_mode[i]=class="num">4;
 }
 else
 {
 m_mode_edit[i].IsLocked(true);
 m_current_mode[i]=class="num">0;
 }
 }
 }
}
 class=class="str">"cmt">//---
 class="type">class="kw">string states[class="num">5]= {"all",">points",">currency","sum>points","sum>currency"};
 for(class="type">int i=class="num">0; i<class="num">6; i++)
 ModeButtonSwitch(m_mode_button[i],lparam,states);
 class=class="str">"cmt">//---
 ModeEditSwitch(lparam,states);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CFastTrading::CloseAllMarketProfit(class="type">int id,class="type">long lparam)
{
 if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[class="num">2].Id()) ||
 (id==CHARTEVENT_KEYDOWN && lparam==KEY_C))
 {
 class=class="str">"cmt">//--- declare the request and the result
 class="type">MqlTradeRequest request;
 class="type">MqlTradeResult result;
 class="type">int total=PositionsTotal(); class=class="str">"cmt">// the number of open positions
 class="type">int sum_pp=class="num">0;
 class="type">class="kw">double sum_cur=class="num">0.0;
 class=class="str">"cmt">//--- Calculate profit for modes class="num">4 and class="num">5
 if(m_current_mode[class="num">0]>class="num">2)
 {
 for(class="type">int i=total-class="num">1; i>=class="num">0; i--)
 {
 class=class="str">"cmt">//--- order parameters
 class="type">class="kw">ulong position_ticket=PositionGetTicket(i); class=class="str">"cmt">// position ticket

按魔术码与品种归集浮盈点数

遍历持仓时,先用 PositionGetString(POSITION_SYMBOL) 取出品种、PositionGetInteger(POSITION_MAGIC) 取魔术码,再用 PositionGetInteger(POSITION_TYPE) 判定多空方向。利润与库存费分别走 PositionGetDouble(POSITION_PROFIT) 和 POSITION_SWAP,这两项是账户货币计值,和后面的点数要分开算。 点数换算看方向:买单用 (SYMBOL_BID - 开仓价)/_Point,卖单用 (开仓价 - SYMBOL_ASK)/_Point,强转 int 后得到 profit_pp。若当前图表品种与持仓品种一致且魔术码等于 m_magic_number,才进入模式分支。 模式 3 把 profit_pp 累加到 sum_pp,模式 4 把 profit_cur+swap 累加到 sum_cur。这意味着同品种同魔术码的持仓,在模式 3 下只统计点数、不碰金额;模式 4 则忽略点数、只统计净值含隔夜费。 实际验证时把 m_current_mode[0] 在 3 和 4 之间切一下,观察 sum_pp 与 sum_cur 的输出差异,能直接看清 EA 到底在按哪种维度管仓。外汇与贵金属杠杆高,库存费在跨周时会显著改变 sum_cur,回测和实盘都建议单独打印 swap 字段。

MQL5 / C++
class="type">class="kw">string position_symbol=PositionGetString(POSITION_SYMBOL);              class=class="str">"cmt">// symbol
class="type">class="kw">ulong  magic=PositionGetInteger(POSITION_MAGIC);                            class=class="str">"cmt">// position MagicNumber
class="type">ENUM_POSITION_TYPE type=(class="type">ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); class=class="str">"cmt">// position type
class="type">class="kw">double profit_cur=PositionGetDouble(POSITION_PROFIT);
class="type">class="kw">double swap=PositionGetDouble(POSITION_SWAP);
class=class="str">"cmt">//---
class="type">int profit_pp;
if(type==POSITION_TYPE_BUY)
   profit_pp=class="type">int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point);
else
   profit_pp=class="type">int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point);
class=class="str">"cmt">//---
if(magic==m_magic_number)
   if(position_symbol==Symbol())
   {
      class="kw">switch(m_current_mode[class="num">0])
      {
      case  class="num">3:
         sum_pp+=profit_pp;
         class="kw">break;
      case  class="num">4:
         sum_cur+=profit_cur+swap;
         class="kw">break;
      }
   }
class=class="str">"cmt">//--- iterate over open positions
for(class="type">int i=total-class="num">1; i>=class="num">0; i--)
{
   class=class="str">"cmt">//--- order parameters
   class="type">class="kw">ulong  position_ticket=PositionGetTicket(i);              class=class="str">"cmt">// position ticket

常见问题

优先检查面板初始化与按钮工厂函数是否成功创建对象,若返回空说明资源未分配,需重跑初始化并看日志报错。
改挂单面板的输入框与窗口初始化里的控件宽高参数即可,注意同步调整相邻按钮的布局坐标避免重叠。
可以,小布能读取你的面板配置并提示按钮切换时编辑框参数联动的异常,省去你手动逐行核对。
是按钮切换时编辑框的参数联动没写全,需在模式切换事件里显式重设编辑框值和可见性。
在平仓面板的盈利模式分支中选按魔术码与品种归集,填入对应魔术码和品种,再用一键清仓只平满足条件的浮盈点数单。