我们已经知道如何使用变量这个“小抽屉”来存东西了,但现在有一个新问题:这个抽屉应该放在哪里?是放在某个房间里,还是放在客厅中央?
放在不同的地方,决定了谁能用它、谁看不见它。这就是变量的作用域,也就是变量的“有效范围”或“活动区域”。
为了方便理解,我们来打个比方。假设你的EA程序是一栋房子,房子里的每个函数(function
)都是一个独立的房间(比如厨房、客厅)。
在这栋房子里,我们有三种不同的“通讯工具”(变量):
- 局部变量:一个只在厨房里能用的对讲机。
- 全局变量:一套安装在整栋房子里,所有房间都能用的中央广播系统。
- 静态变量:一本放在厨房里,每次进出内容都不会被擦掉的记事本。
搞清楚这三种工具的区别和用途,是写出结构清晰、运行稳定的EA的关键。
① 局部变量:房间里的对讲机
局部变量,是定义在某一个函数 {}
内部的变量。
它的特点是“用完即焚”:只在当前这个函数运行时“出生”,函数一结束它就立刻“消失”了,内存被释放。就像你在厨房里喊话,出了厨房就没人听得见了。
void MyFunction()
{
int kitchenCounter = 5; // 这个变量只在MyFunction这个“厨房”里有效
Print(kitchenCounter);
}
什么时候用它?
绝大部分时间!它是我们最常用的变量类型。主要用于临时的计算和存储。比如,在一个计算持仓风险的函数里,你需要几个变量来临时存放账户余额、风险比例、计算出的金额等,这些都应该是局部变量,因为计算任务一完成,这些中间值就没用了。
② 全局变量:整栋房子的广播系统
全局变量,是定义在所有函数之外的变量,通常我们习惯把它写在代码文件的最顶部。
它的特点是“生命力顽强”:从EA加载开始就“出生”,直到EA被移除才“消失”。在EA运行的整个期间,房子里任何一个房间(函数)都可以随时使用它、修改它。
// === 全局设定 ===
int MagicNumber = 8888; // 这是一个全局变量,定义在所有函数之外
void OnTick()
{
Print("当前魔术号是: ", MagicNumber); // 在OnTick函数里可以访问
}
void CheckOrders()
{
if(OrderMagicNumber() == MagicNumber) // 在另一个函数里也可以访问
{
// ...
}
}
什么时候用它?
当我们有一些核心的、需要被多个函数共享的“公共设置”时。最典型的就是EA的输入参数,比如用户设置的手数
、止盈
、止损
、魔术号
、风险百分比
等。把这些定义成全局变量,就可以方便地在开仓、平仓、风控等不同功能的函数里调用。
③ 静态变量:房间里的“记忆”记事本
静态变量是一种很特殊的局部变量。它同样定义在函数内部,但前面加了一个static
关键字。
它的神奇之处在于,它具备了“记忆能力”。函数结束后它不会“消失”,它会一直保留着上一次的值,直到整个EA程序结束。但同时,它又像局部变量一样,只有在定义它的那个函数内部才能被访问。就像一本放在厨房的私人记事本,客厅里的人是看不到的。
void OnTick()
{
// 这个count变量只在OnTick函数里有效,但它的值会在每次Tick之间被保留
static int count = 0;
count++;
Print("OnTick函数被调用了 ", count, " 次");
}
每次价格跳动,OnTick
函数被调用时,count
的值都会在上次的基础上+1
,而不是每次都重新变回0。
什么时候用它?
当你需要让一个函数“记住”它上次干了什么的时候。这是一个非常强大的功能。比如:
- 实现“每根K线只交易一次”的逻辑。
- 统计某个条件连续触发了多少次。
- 记录上一次的指标值,用于和当前值进行比较。
学长避坑指南:请警惕全局变量的滥用!
新手程序员最容易犯的错误,就是为了图方便,把所有变量都设置成全局的。这在短期看似简单,但当你的EA代码超过几百行后,将是一场灾难。
一个可以被任何函数随意修改的全局变量,会让你的程序逻辑变得混乱不堪。你很难追踪一个值的改变到底是在哪里发生的,一个地方的修改可能会意外地影响到另一个完全不相干的功能,这种BUG极难排查。
核心原则:永远优先使用局部变量。只在“必须被多个函数共享”的情况下,才考虑使用全局变量。如果一个需要“记忆”的变量只在一个函数内部使用,那就用静态变量,而不是全局变量。