内容 |
函数类型 (1) 函数特点 (2) 添加一个函数 (3) 定义一个数据源 (4) 函数周期 (5) 函数周期对齐 (6) 派生自定义函数(仅VCL) |
7.1 函数类型
7.1.1 函数特点
一个TeeChart Pro函数是一个序列,它几乎可以是任何序列类型,它可以应用一个代数函数,而数据源是另一个图表序列。
所有函数都源自于TteeFunction组件,并且继承了TeeFunction的Period(期间)属性。
TeeChart Pro包括下面的预定义函数列表。为了得到所有函数类型的完整列表,请查看TeeChart编辑器库Gallery(画廊)和Helpfile(帮助文件):
函数类型 | 输入的数量 | 描述 |
Add(添加) | 无限制 | Plots sum of inputs |
Average(平均) | 无限制 | 平均函数,将计算每一组期间点的平均值 |
Bollinger(布林线) | 1 | 布林函数,使用简单或指数移动平均值来构造Bollinger Trading Bands(布林交易带_布林线)。 |
Copy(复制) | 1 | 输入序列的直接拷贝 |
Curve Fitting (曲线拟合) | 1 | 通过使用TypeFitting公式的数据输入来绘制拟合多项式 |
Divide(除) | 无限制 | The Divide Function plots inputs divided in descending order of inclusion |
Exponential Average(指数平均数) (指数平均数) | 1 | 指数平均数基于Weight(权重) |
Exponential Moving Average (指数移动平均数) | 1 | 指数移动平均数基于Weight(权重) |
Exponential Trend (指数趋势) | 1 | 通过输入序列中的点画出最佳的指数趋势线 |
High(高) | 无限制 | 高函数,绘制输入的最高点 |
Low(低) | 无限制 | 高函数,绘制输入的最低点 |
MACD | 1 | 平滑异同移动平均线 |
Momentum(动量) | 1 | 动量指标MTM,每一个Y值都是当前点的Y值而不是上一个周期点的Y值。M=(Y/Y’) |
Momentum Division (动量除) | 1 | 每一个Y值都是当前点的Y值除以最后一个周期点的Y值,以百分比表示 |
Moving Average (移动平均数) | 1 | 移动平均函数,将计算每一组周期点的简单或加权平均 |
Multiply(乘) | 无限制 | 乘函数,画输入值的乘 |
Root Mean Square (均方根) | 无限制 | 根均方根函数,画输入值的RMS(均方根值) |
Relative Strength Index (相对强弱指数) | 1 | RSI函数根据财务数据计算一个百分比值。根据TRSISyle类型不同的公式将被用来计算RSI值 |
Standard Deviation (标准差) | 1 | 绘制每一组周期点的标准偏差(或完全标准差) |
Stochastic(随机指标) | 1 |
|
Subtract(差集) | 无限制 | 画出按降序排列减去输入的值。 |
Trend(趋势) | 1 | Draws best trend line through points of input Series通过输入序列点绘制最佳趋势线 |
一些函数类型只支持一个输入序列。然而,可以链连函数是可能的,例如,在您的图表中使用几个序列的平均值来创建一个平均的函数序列,然后通过使用Average(平均)函数作为Trend(趋势)函数的输入来确定平均值的趋势。
7.1.2 添加一个函数
使用图表编辑器,在第一个图表页面中,选择Add(添加)按钮,就好像在图表中添加一个新序列。在TeeChart的Gallery(画廊)中,选择Function(函数)选项卡来选择您需要的函数。每个函数都被作为一个LineSeries(线序列)呈现,您可以通过在第一个图表页面上选择change(改变)按钮来更改与该函数相关联的序列类型。函数定义在FunctionSeries(函数序列)的Datasource页面上很容易更改。在这里,同样容易地,您可以将您添加到图表的普通序列的定义更改为函数的定义(函数实际上是一个datasource的定义,而不是一个序列类型的定义)。
下图显示了在编辑函数时的Datasource(数据源)页面。定义了Line Series(线序列)(名为“Series2”、标题“Average(平均值)”)。Datasource页面底部的左边列表框显示了可用于输入的图表中的其他序列(这里是“Series1”)。
假设我们从一个完全空白的图表开始,这是构建一个简单的Series-Function(序列-函数)相关图表的代码步骤。
procedure TForm1.BitBtn5Click(Sender: TObject);
var tmpBarSeries1,
tmpBarSeries2 : TBarSeries;
tmpLineSeries : TLineSeries;
begin
//添加2数据序列
tmpBarSeries1:=TBarSeries.Create(Self);
tmpBarSeries2:=TBarSeries.Create(Self);
AddSeries(tmpBarSeries1);
AddSeries(tmpBarSeries2);
//用数据填充它们(这里是随机的)
tmpBarSeries1.FillSampleValues(10);
tmpBarSeries2.FillSampleValues(10);
//添加一个用于Average(平均)函数的序列
tmpLineSeries:=TLineSeries.Create(Self);
AddSeries(tmpLineSeries);
//定义新序列的函数类型
tmpLineSeries.SetFunction(TAverageTeeFunction.Create(Self));
//定义新函数序列的Datasource
//接受了其他两个序列的序列标题
tmpLineSeries.DataSources.Clear;
tmpLineSeries.DataSources.Add( tmpBarSeries1 );
tmpLineSeries.DataSources.Add( tmpBarSeries2 );
// *注意--当手动填充输入序列时,需要使用Checkdatasource方法
//—参见题为“Defining a Datasource(定义数据源)”的部分。
//改变函数的周期使其平均每2个点为一组
tmpLineSeries.FunctionType.Period := 2;
end;
我们可以添加另一个函数来告诉我们有关前一个的函数的一些事情。
procedure TForm1.BitBtn6Click(Sender: TObject);
var tmpHighLine : TLineSeries;
begin
//添加另一个用于第二个函数的序列
tmpHighLine:=TLineSeries.Create(Self);
AddSeries(tmpHighLine);
//定义新序列的函数类型
tmpHighLine.SetFunction(THighTeeFunction.Create(self));
//定义新函数序列的Datasource ,用现有的函数(tmpLineSeries)作为输入。
//如果你想在程序之间使用它,您应该向模块全局地声明tmpLineSeries
tmpHighLine.DataSource := tmpLineSeries;
//在默认值0(没有Period(周期)设置)的情况下,在平均函数的所有点的最高处绘制一条线
end;
7.1.3 定义一个数据源
上一节中的例子强调了使用Datasource来通过代码来进行函数的使用。序列使用Datasource定义一个函数的输入,或者定义一个序列TDataset数据源(参见关于访问数据库的教程)。
使用图表编辑器,在添加一个函数之后,函数序列的“Datasource页面”将显示一个包含在函数定义中的可用序列的列表。在这里,你可以改变你想要应用到这个序列的函数类型,并从左边的列表框“Available(可用)”中选择序列,并将它们添加到右边的列表框“Selected(已选择)”中。
通过代码使用 Series.Datasource 属性的数据源。示例
假设我们在一个图表中有两个数据序列。我们使用图表编辑器来添加一个由2个序列的平均值组成的函数;
我们在这两个系列中添加了一些点:var t : Integer;
For t := 0 To 10 do
begin
Series1.Add(2 * t);
Series2.Add(3 * t);
end;
注意,这个函数没有显示。你需要使用这个Series.CheckDatasource方法来读取函数的值。
Series3.CheckDataSource; //读取函数中的数据
函数定义可以在运行时被改变,使用Setfunction方法将一个新函数分配给序列。
Series3.Setfunction(TMovingAverageFunction.Create(self));
使用上面的代码行,Setfunction将Series3的函数更改为Moving Average(移动平均值)。
7.1.4 函数周期
Period(周期)是处理函数的一个重要属性,因为周期定义了一个函数在周期性的应用中的点的范围。
示例
我们有6个有值的数据点(例如,BarSeries(条棒序列)的条棒): 3、8、 6、 2、9 、 12
我们定义了一个周期为0(默认)的函数序列,平均值画的是:6.667
当周期为2时,我们得到了3个平均值作为函数的输出值: 5.5、 4 、 10.5
这些值将在它们的周期范围内的中心绘制。第一个值在输入序列的1和2之间,第2个值在3和4之间,等等。
您可以通过在图表编辑器中选择函数来定义周期,也可以使用函数类型在运行时修改周期。
例如,第2序列是函数序列:
Series2.FunctionType.Period:=2;
下面是两个图表,突出了应用了周期的效果
7.1.5 函数周期对齐
当函数“Period(周期)”大于0时(因此它由一组点来计算),函数结果在函数周期的“中心”位置被默认添加到序列中。在整个周期空间内,PeriodAlign属性控制“哪里”来放置函数计算后的位置。
TeeFunction1.PeriodAlign := paCenter ; { <--默认情况下它是居中的}
“paFirst”和“paLast”常数将在每个“周期”的开始和结束的“X”坐标中进行标绘计算。每一个蓝色的点都显示了在每个月的第一天到最后一天之间的所有点的“average(平均数)”。
PeriodAlign= paLast //正如你从下图所看到的,“average(平均数)”是在月末绘制的。
PeriodAlign =paFirst //在这种情况下,“average(平均数)”是在月初绘制的。
7.1.6 派生自定义函数(仅VCL)
创建一个新的函数组件仅仅是创建一个从TTeeFunction派生的新组件(它也可以从一个现有的函数派生出来)。在TTeeFunction中有两个重要的虚拟方法可以被覆写来创建一个新的函数类型。
1) Function TTeeFunction.Calculate(SourceSeries:TChartSeries;First,Last:Longint):Double;
2) FunctionTTeeFunction.CalculateMany(SourceSeriesList:TList; ValueIndex:Longint):Double;
如果只有一个序列是数据源,那么Calculate方法是用来计算函数结果的。如果多个序列可以是数据源,则用CalculateMany来计算函数结果。
示例:创建新的TMyFunction
让我们决定需要 TMyFunction 来返回 “ 平方和 ” 。type
TMyFunction = class( TTeeFunction )
end;
这个函数有一个数据源或多个数据源,因此我们将重写Calculate和CalculateMany方法。
首先,我们将重写TMyFunction“Calculate”方法来做一个非常简单的事情。“Calculate”方法看起来是这样的:
Function TMyFunction.Calculate(SourceSeries:TChartSeries; First,Last:Integer):Double;
Var StartPoint, EndPoint, t : Integer;
begin
StartPoint:=0;
EndPoint:=SourceSeries.Count-1;
if First <> -1 then StartPoint:=First;
if Last <> -1 then EndPoint:=Last;
Result:=0;
for t:=StartPoint to EndPoint do
Result:= Result + Sqr(SourceSeries.MandatoryValueList[t]);
end;
StartPoint和EndPoint变量用于“循环”所有的SourceSeries点来计算平方和。
“MandatoryValueList”属性被用来代替“YValues”属性,只是为了让这个函数与诸如HorizBarSeries之类的序列类型一起工作,在这里“XValues”保持点值而不是“YValues”。
当这个序列只有一个序列作为数据源时,就会使用“Calculate”方法。当序列有多个序列作为数据源时,就会调用“CalculateMany”方法。
以允许 TMyFunction 与具有多个序列作为数据源的序列一起工作。通过编程的方式,可以将序列添加为其他序列的数据源。Function TMyFunction.CalculateMany(SourceSeriesList:TList; ValueIndex: Integer):Double;
var t : Integer;
begin
Result:=0 ;
for t:= 0 to SourceSeriesList.Count -1 do
Result := Result + sqr(TChartSeries(SourceSeriesList[t]).MandatoryValueList[ValueIndex]);
end;
“CalculateMany”将会在源序列的每一个点上被调用一次,从零开始,最后以所有数据源的最小点计数结束。
理解Calculate和CalculateMany之间的区别是非常重要的。“Calculate”在只有一个数据源时被调用,它只被调用一次。当有多个序列作为数据源时,“CalculateMany”被调用多次(每个点的一个)。
第七章 完