#### 平台函数

##### 内容

- 自有数据维护函数
- 平台函数简介
- 平台执行信息
- 用户和函数相关函数
- 平台与客户端交互函数

##### 自有数据维护函数

###### 内容

- LoadTableEx
- UserDB
- LoadTable
- SaveTable
- TestTable
- SaveBk
- DeleteBk
- ListTable
- DeleteTable

###### LoadTableEx

用途：自有数据维护函数相关函数。
参数：arg1（按示例顺序传入）。
返回：处理后的结果值。

范例

```tsl
return LoadTableEx('repitle');
```

返回:repitle为保存好的用户数据

###### UserDB

####### 内容

- UserDataUpLoad
- HexToString
- TransFileName

####### UserDataUpLoad

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
// dir为用户本地用户数据的存贮目录
Filedir := 'C:\\Users\\xxxx\\Tinysoft\\Analyse.NET\\D254A848\\xxx\\UserDB\\hex_74657374646174613031.stm';
return UserDataUpLoad(Filedir); // 返回上传结果提示信息。
```

####### HexToString

用途：将输入值转换为字符串。
参数：

返回：字符串。

范例

```tsl
// 将用户数据名转化为可读串
str := 'hex_74657374646174613031.stm';
return HexToString(str); // 返回testdata01
```

####### TransFileName

用途：自有数据维护函数相关函数。
参数：

返回：整数。

范例

```tsl
// 获取本地用户数据列表
dir := 'C:\\Users\\xxxx\\Tinysoft\\Analyse.NET\\D254A848\\xxx\\UserDB';
return TransFileName(dir); // 返回用户数据列表
```

###### LoadTable

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
// 将savetable范例中保存的用户数据testA提取出来
return LoadTable('testA');
```

参考TestTable SaveTable ListTable DeleteTable

###### SaveTable

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

注意：

在保存用户数据的时候可以分目录保存，只需在目录层次间添加‘\\’即可;在不同的目录下可以将数据保存为相同的数据名称。

另外，该目录的分类方法在左上角工具栏中的“数据”可查看到分类，但是在资源管理器中，只以"目录名\数据表名"显示

范例

范例一：直接在根目录下保存

```tsl
// 将r保存为用户数据testA
r := rand(10, 10);
return SaveTable('testA', r);
// 结果：-1
```

范例二：保存到指定目录下

```tsl
// 将生成的10行10列的随机数据保存到目录：mydata\目录下，保存
// 文件名称为testA
r := rand(10, 10);
ret := SaveTable('mydata\\testA', r);
return ret;
// 结果：-1
```

用户数据的查看：

用户可以在左上角菜单栏的‘数据’中查看保存的数据，如果保存后即时查看，服务器还没有把数据推送到客户端，用户需要主动查询用户数据，点击左上角菜单栏‘系统’－>‘检查用户数据’，右下角弹出最新更新的用户数据后，再点击菜单栏‘数据’，即可看到刚刚存入的数据。

范例三：新旧流格式数据保存操作及结果对比，在新版客户端+下一代服务器下执行以下操作

```tsl
t := getdatademo(); // 返回一个数组--测试者数据举例
r1 := SaveTable("TestSTData01", t); // 缺省情况下保存用户数据
r2 := SaveTable("TestSTData02", t, 0); // 指定保存为原始流格式
r3 := SaveTable("TestSTData03", t, 1); // 指定保存为新流格式
return array(r1, r2, r3);
```

保存后，用户数据中列表大小显示如下：新流格式数据大小为源始流格式的55%，数据大小有明显的变小

关于新流格式：

新一代客户端上传用户数据采用快速流，为了客户端保持和古旧的平台的兼容性，原有客户端上传的数据依旧采用原始流模式。

如果同时使用老旧的客户端（2020年6月之前的版本）和新的客户端，老旧客户端无法处理新的流模式。

新版本的执行返回结果集使用用的是快速流格式，快速流模式空间需求小，且加载效率快300%。

参考TestTable LoadTable ListTable DeleteTable

###### TestTable

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
return TestTable('testA'); // 测试用户数据"testA"是否存在。返回值为1，即存在，0即不存在。
```

参考SaveTable LoadTable ListTable DeleteTable

###### SaveBk

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
SaveBk("MySector", "我的一级分类\\我的二级分类", array("SZ000001", "SZ000002"));
{在"我的一级分类\\我的二级分类"目录生成一个名为"MySector "的板块，该板块的成分为SZ000001,SZ000002}
```

参考DeleteBk

###### DeleteBk

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
DeleteBk("MySector");
```

参考SaveBk
http://www.tinysoft.com.cn/TSDN/HelpDoc/SearchContent.tsl?r=ref&KeyWord=

###### ListTable

用途：自有数据维护函数相关函数。
参数：无。
返回：处理后的结果值。

范例

```tsl
return ListTable();
```

结果如下：

参考TestTable SaveTable LoadTable DeleteTable

###### DeleteTable

用途：自有数据维护函数相关函数。
参数：

返回：处理后的结果值。

范例

范例一：删除指定目录下的用户数据

```tsl
// 删除存在目录：“mydata\目录下”的用户数据testA
ret := DeleteTable('mydata\\testA');
return ret;
// 结果：-1
```

范例二：删除同一规则命名的用户数据

```tsl
// 删除存在目录：“mydata\目录下”以test开头命名的用户数据
data := listTable();
for i := 0 to length(data) - 1 do
begin
    if pos('mydata\\test', data[i]) > 0 then
    begin
        DeleteTable(data[i]);
    end;
end;
return listtable();
```

参考TestTable SaveTable LoadTable ListTable

##### 平台函数简介

平台函数指天软金融分析.NET平台专用函数（证券相关等函数也是平台专用函数）

##### 平台执行信息

###### 内容

- TSCanGrid
- Isbackground
- tsAppServer
- TsAppServerName
- SendToClient
- TS_ModuleInfo

###### TSCanGrid

###### Isbackground

###### tsAppServer

用途：平台执行信息相关函数。
参数：无。
返回：处理后的结果值。

范例

```tsl
a := rand(10, 10);
return tsAppServer();
// 结果：192.168.101.45:3328(Z:\server\bin5)
```

###### TsAppServerName

用途：平台执行信息相关函数。
参数：无。
返回：处理后的结果值。

范例

```tsl
return TsAppServerName();
```

结果：192.168.101.26:z:\server\bin\exec64.exe

###### SendToClient

用途：平台执行信息相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
// 1)执行命令：return 100+1
return SendToClient("getdo", "return 100 + 1;", nil, nil);
// 结果：101
// 2)采用系统参数取得数据，将取得的数据相加，并设置超时时间为30s
return SendToClient("getdo", "return getsysparam('a') + getsysparam('b');", nil, array("a":10, "b":30), 30);
// 结果：40
```

参考平台和客户端交互。

###### TS_ModuleInfo

用途：平台执行信息相关函数。
参数：无。
返回：处理后的结果值。

范例

```tsl
return TS_ModuleInfo();
```

差异说明Windows：任何版本。

Linux：自2024-07-10之后的版本，开始支持；之前的版本不支持。

##### 用户和函数相关函数

###### 内容

- User
- UserName
- FunctionType
- FunctionName
- FunctionVer
- UserConfig
- SetUID
- SUDO

###### User

用途：用户和函数相关函数相关函数。
参数：

返回：处理后的结果值。

范例

```tsl
// 执行用户jrtzsupport 共享的大师策略的函数Show_DSXG_211
begt := inttodate(20130101);
endt := inttodate(20140101);
return User('jrtzsupport').Show_DSXG_211(begt, endt, 0);
```

参考SYSTEM

###### UserName

###### FunctionType

参考FunctionName FunctionVer

###### FunctionName

参考FunctionType FunctionVer

###### FunctionVer

参考FunctionType FunctionName

###### UserConfig

###### SetUID

###### SUDO

##### 平台与客户端交互函数

###### 内容

- 在平台模型运行时打印信息到客户端/Web端
- 平台模型远程调用客户端函数，访问客户端的资源
- SendToClient提供调用本地命令

###### 在平台模型运行时打印信息到客户端/Web端

在运行平台模型的时候，为了调试方便，也为了监控模型的正常运行，往往需要知道模型运行的状态，这样我们需要在模型运行过程中输出一些信息到终端，而不是等待模型执行完毕得到最终结果。

这就需要使用打印信息到客户端的功能。

我们看一个案例，这个案例就是获得每个股票的Beta值：

```tsl
Stks := GetBk("深证A股;上证A股");
Result := array();
for i := 0 to length(Stks) - 1 do
begin
    SetSysParam(pn_Stock(), Stks[i]);
    Result[i]["StockID"] := Stks[i];
    Result[i]["Beta"] := StockBeta4("SH000300", 10); // 最近一年的Beta
    Echo Result[i]["StockID"], "->", Result[i]["Beta"];
end;
return Result;
```

由于调用Beta的时候，计算效率会稍微低，我们利用Echo把当前运行的信息打印到了客户端，客户端的窗口内容如下：

利用这样的方法，我们就可以实时知道当前模型运行的状况了。我们在很多地方可以用到这个功能，例如我们可以简单地打印几个时间或者运行的时间长短来知道运行的效率。

对于运行中间得到的结果是一个复杂结果的，例如数组等内容，那么就没办法直接Echo这个结果，这就要结合tostn函数来输出调试了。

```tsl
Stks := GetBk("深证A股;上证A股");
Result := array();
for i := 0 to length(Stks) - 1 do
begin
    SetSysParam(pn_Stock(), Stks[i]);
    Result[i]["StockID"] := Stks[i];
    Result[i]["Beta"] := StockBeta4("SH000300", 10); // 最近一年的Beta
    Echo tostn(Result);
end;
return Result;
```

每一行的内容会显示在右边部分，这个时候我们可以利用转换数据按钮把字符串以数据的方式来显示。

除了Echo以外，我们还可以利用Writeln或者Write函数来输出这些内容。

当我们不是在终端上运行这些模型，而是在WEB端或者独立解释器里调用运行这个模型，信息会直接输出到浏览器或者控制台中。

参考：echo

###### 平台模型远程调用客户端函数，访问客户端的资源

我们在使用平台模型的时候，经常有需要要访问客户端本地资源。打个比方，我们需要导出计算的数据，而等待整个模型的返回特别长，所以可能我们需要边运行，边导出数据。又或者整个的数据结果集非常大，无法单次返回，需要分开成小结果集运行时导出到客户端，而导出数据可以通过ExecSql输出到数据库，也可以是通过ExportFile来导出文件，我们还可以通过WriteFile等文件读写函数来直接操作文件。以及通过封装好的系统或者用户写的TSL函数。

平台提供了两个关键字RDo和RDo2来解决这个问题。RDo和RDo2可以在平台运行模型的时候远端调用客户端的函数运行。

例如：我们在运行的时候要导出一组股票的交易明细数据到客户机上。

```tsl
Stks := GetBK("深证A股;上证A股");
Day := Today();
for i := 0 to length(Stks) - 1 do
begin
    SetSysParam(pn_Stock(), Stks[i]);
    if not isTradeDay(Day) then continue; // 如果没有交易则下一个
    Data := select DateTimeToStr(["date"]) as"Time", ["close"], ["vol"] from tradetable DateKey Day to Day + 1 of Stks[i] where ["vol"] > 0 end; // 取出时间，收盘价，成交量
    RDo2
    ExportFile(ftCSV(), "", "C:\\DataStore\\" + IntToStr(DateToInt(Day)) + "\\" + Stks[i] + ".csv", Data); // 导出数据
end;
```

以上代码为将上证和深证A股的当天的交易明细导出到本地。ExportFile是一个导出的函数，但是在平台上运行的时候导出到的位置是在服务器上，而且需要在服务器上设置权限。而用RDo2则使导出命令在客户端上运行，所以输出会在客户端本地。

由于要对本地文件进行读写，或者调用本地的其他资源，终端为了安全起见，默认禁止了这类远端调用，于是系统左上角会出现如下界面：

系统还会终止模型的运行并且返回出错信息。

用户可以通过菜单进入系统设置，也可以点击进入系统信任中心，界面如下：

信任中心的初始是最高安全性，禁止了远程模型对本地资源的访问。如果我们只需要导出数据到本地或者执行本地的数据库查询语句，那么我们可以选择高安全性，高安全性允许RDO/RDO2执行的函数是ExportFile和ExecSQL。

如果我们还需要从本地导入数据，调用ImportFile函数，则应该设置为中安全性。低安全性则是允许RDo/RDo2调用任何本地函数。而最低安全性则还允许使用SendToClient函数用”do”或者”getdo”命令组成命令串执行，这就可以不需要把命令串封装成函数来执行。

如果信任中心拒绝了调用，系统会自动禁止该调用，并且会有一个禁止掉的提示小窗口。而当信任中心允许调用的时候，如果用户没有进行许可设置，系统依旧会对远程模型的本地资源调用进行安全提示。

我们可以信任某个用户来源的所有的函数的调用，也可以信任该来源函数的调用，还可以仅仅信任该调用（例如信任导出的调用必须导出的文件名都是一致的），我们还可以临时允许该调用或者拒绝该调用。这样下次当调用发生的时候，该信任管理窗口依旧会出现。

对于导入和导出的调用，还有一个信任路径的设置。当设置了信任路径以后，在该信任路径下以及该路径下的子目录下的所有导入/导出命令将会被允许而不再提示。

无论是拒绝还是信任了，在运行信息中总是会显示收到的命令。此外，对于已经设置了信任的调用方式，如果用户需要修改，可以进入系统设置中，打开信任配置文件来修改INI文件，找到相应项目删除掉就可以了。

RDo和RDo2的差异在于RDo2会返回函数的执行结果，因此RDo2是同步执行的方式，一定会等待客户端执行完毕才返回。而RDo则是不返回结果，直接把命令提交给客户端处理，至于执行的正确与否，RDo是不理会的，会出现模型执行完毕了，而客户端的命令仍然在排队执行的情况。

在绝大多数情况下，RDo2会更安全可靠，但是RDo的效率有时候会更高。但是平台会约束RDo送回到客户端的内容的带宽，并且系统也无法保障RDo的执行是否是正确的。

而且有些函数是必须用RDo2的，例如ImportFile，因为不用RDo2，该调用毫无意义。而ExportFile,ExecSQL的调用，有点却不一定需要等待返回，所以也可以采用RDo，但是我们依旧推荐用户使用RDo2，除非用户确实需要使用RDo。

如果RDo2所调用的函数使用了系统参数（客户端执行的函数并不多见），则可以使用With关键字把系统参数带进去。

例如A:=RDo2 LocalFunctionTest() with array("abcd":123,"bcd":234);

而LocalFunctiontest函数的内容则为:

Return GetSysParam("abcd")+GetSysParam("bcd");

则返回的结果是357

RDo2调用的默认是300秒超时的，也就是说默认情况下当客户端未能在300秒内处理完请求（包括客户端无人响应确认），系统会抛出超时的异常。

如果需要设置超时的时间，可以用TimeOut来设置超时，例如RDo2
ImportFile(ftCsv(),"","C:\\1.csv",Data) TimeOut 30;
调用ImportFile函数的超时时间为30秒。

参考：RDo,RDo2

###### SendToClient提供调用本地命令

RDo和RDo2提供了调用本地函数的功能，但是有时候一个计算不一定要用函数，例如：执行一个1+1的操作。这类需求利用SendToClient可以完成。

SendToClient提供了很灵活的调用方法，事实上RDo,RDo2也是通过SendToClient函数来实现的。SendToClient实现了如下命令：

echo 显示信息

import 导入

export 导出

rdo 远程调用

rdo2 远程调用并返回

do 远程执行命令串

getdo 远程执行命令串并返回

由于echo命令、import、export、rdo、rdo2命令在之前都有相应的简单的替代方案，因此，我们就只讲do、getdo命令的使用。

例如，我们要用本地计算一个1+1的值，我们可以采用如下方法:

Return SendToClient("getdo","return 1+1;",nil,nil);

如果在计算中需要采用系统参数,将参数放入第四个参数即可：

Return SendToClient("getdo","return
getsysparam('a')+GetSysParam('b');",nil,array("a":1,"b":2));

如果计算数据的超时时间需要设置，再在后边加入一个超时的秒数的参数：

Return SendToClient("getdo","return
getsysparam('a')+GetSysParam('b');",nil,array("a":1,"b":2),30);//超时为30秒。

do命令和getdo命令类似，但是do命令不等待结果的返回，这点和RDo与RDo2的差异类似。

参考：SendToClient
