# 第三方交互 / TS-OPI

## `tsgetsessionname()`

声明：function

返回当前租户名称；适用于同一函数可能由不同租户调用的场景

<!-- tags: 执行 开放接口 会话调用 跨账号调用 -->

返回：string

## `tsgetapiname()`

声明：function

返回当前 API 用户名

<!-- tags: 开放接口 会话调用 跨账号调用 -->

返回：string

## `tenantCall(session_key, call_name, param, timeout)`

声明：function

调用已创建租户公开的接口，不需要取得租户接口的具体实现

<!-- tags: 查询 执行 开放接口 会话调用 跨账号调用 -->

| 参数          | 类型    | 说明                                                          |
| ------------- | ------- | ------------------------------------------------------------- |
| `session_key` | string  | 租户的 SESSION-KEY；租户设置密码时使用 `SESSION-KEY:PWD` 形式 |
| `call_name`   | string  | 租户公开的调用名称；空字符串表示使用默认调用                  |
| `param`       | array   | 传给租户接口的参数数组                                        |
| `timeout`     | integer | 可选。调用超时时间，单位为毫秒                                |

返回：any

### 示例

范例01：使用掩码租户 SESSION-KEY 调用接口；需已为该租户配置调用权限

```tsl
session_key := "{58DC***DF58}";
return tenantCall(
    session_key,
    "HQData",
    array("StockID": "SZ000002")
);
```

## `opsCall(call_name, ops_name, param, timeout)`

声明：function

调用 TS-OPS 服务上的函数，并返回可取得最终结果的网格结果对象

<!-- tags: 查询 执行 分布式计算 并行执行 开放接口 会话调用 跨账号调用 -->

| 参数        | 类型    | 说明                                                                       |
| ----------- | ------- | -------------------------------------------------------------------------- |
| `call_name` | string  | OPS 服务提供的函数名称                                                     |
| `ops_name`  | string  | 注册时由 TS-OPS-ID 定义的服务名；空字符串表示使用支持该函数的默认 OPS 服务 |
| `param`     | array   | 传给 OPS 函数的参数数组                                                    |
| `timeout`   | integer | 可选。调用超时时间，单位为毫秒                                             |

返回：grid_result

### 示例

范例01：调用已启动的 OPS 服务；需对应服务已注册并保持运行

```tsl
return opsCall(
    "hahaha",
    "OPSName1",
    array(10, 3),
    5000
);
```

## `td_opi_getHQData01(stock_id, endt, cy)`

声明：function

获取指定证券、日期和周期的价格与成交量数据

<!-- tags: 查询 价格数据 行情 交易日期 日期时间 开放接口 会话调用 跨账号调用 -->

| 参数       | 类型          | 说明                         |
| ---------- | ------------- | ---------------------------- |
| `stock_id` | string\|array | 证券代码或证券代码集合       |
| `endt`     | t_date        | 计算或查询使用的日期时间边界 |
| `cy`       | string        | 行情或统计周期               |

返回：array

### 示例

范例01：TSL 开发用户调用

```tsl
url := "https://opi.tinysoft.com.cn/Service/Call/TD_opi_getHQData01";
header := "Connection: keep-alive\r\nContent-Type: application/json\r\nTS-EVENTNAME: auto\r\nJSON-Encode: gbk";
arguments := array("StockID": "SZ000002");
session := createHttpSession();
post_data := exportJsonString(arguments);
ok := internetRequest(
    session,
    url,
    "",
    header,
    post_data,
    "tuser",
    "tpassw",
    0,
    result,
    response_code,
    30000
);
echo "ok:", ok, " response_code:", response_code, " result:", result, "\r\n";
destroyHttpSession(session);
```

范例02：Python 开发用户调用

```python
import requests
from requests.auth import HTTPBasicAuth

url = "https://opi.tinysoft.com.cn/Service/Call/TD_opi_getHQData01"
headers = {
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "TS-EVENTNAME": "auto",
    "JSON-Encode": "gbk",
}


post_data = {"StockID": "SZ000002"}
session = requests.Session()
session.auth = HTTPBasicAuth("tuser", "tpassw")
session.headers.update(headers)
response = session.post(url, json=post_data)
print(response.status_code)
print(response.text)
response.close()
```

范例03：MATLAB 开发用户调用

```matlab
url = 'https://opi.tinysoft.com.cn/Service/Call/TD_opi_getHQData01';
data.StockID = ["SZ000002", "SH000300"];
options = weboptions();
options.RequestMethod = 'post';
options.Username = 'tuser';
options.Password = 'tpassw';
options.MediaType = 'application/json';
response = webwrite(url, data, options);
disp(response);
```

范例04：R 开发用户调用

```r
library(httr)

url <- "https://opi.tinysoft.com.cn/Service/Call/TD_opi_getHQData01"
headers <- c(
    "Connection" = "keep-alive",
    "Content-Type" = "application/json",
    "TS-EVENTNAME" = "auto",
    "JSON-Encode" = "gbk"
)
post_data <- list(StockID = "SZ000002")
response <- POST(
    url = url,
    body = post_data,
    encode = "json",
    add_headers(.headers = headers),
    authenticate("tuser", "tpassw", type = "basic")
)
cat(status_code(response), "\n")
cat(content(response, "text", encoding = "gbk"), "\n")
```

范例05：JavaScript 开发用户调用

```javascript
var xhr = new XMLHttpRequest();
var url = "https://opi.tinysoft.com.cn/Service/Call/TD_opi_getHQData01";
var data = JSON.stringify({StockID: ["SZ000002", "SH000300"]});
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.setRequestHeader("username", "tuser");
xhr.setRequestHeader("password", "tpassw");
xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
    }
};
xhr.send(data);
```

范例06：TSL Session-Key 租户调用

```tsl
session_key := "{58DC***DF58}";
url := "https://opi.tinysoft.com.cn/Service/Session/Call/HQData";
arguments := array("StockID": "SZ000002");
header := "Connection: keep-alive\r\nContent-Type: application/json\r\nAuthorization: Bearer " $ session_key $ "\r\nTS-EVENTNAME: auto\r\nJSON-Encode: gbk";
session := createHttpSession();
post_data := exportJsonString(arguments);
ok := internetRequest(
    session,
    url,
    "",
    header,
    post_data,
    "",
    "",
    0,
    result,
    response_code,
    30000
);
echo "ok:", ok, " response_code:", response_code, " result:", result, "\r\n";
destroyHttpSession(session);
```

范例07：Python Session-Key 租户调用

```python
from datetime import datetime, timedelta
import requests

TSL_EPOCH = datetime(1899, 12, 30)

def py_date_to_tsl(value: datetime) -> float:
    return (value - TSL_EPOCH) / timedelta(days=1)

session_key = "{58DC***DF58}"
url = "https://opi.tinysoft.com.cn/Service/Session/Call/HQData"
headers = {
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "Authorization": f"Bearer {session_key}",
    "TS-EVENTNAME": "auto",
    "JSON-Encode": "gbk",
}
post_data = ["SZ000002", py_date_to_tsl(datetime(2026, 3, 25)), "日线"]
response = requests.post(url, headers=headers, json=post_data)
print(response.status_code)
print(response.text)
response.close()
```

范例08：OPS 服务函数实现

```tsl
echo hahaha(1000, 9999);

function hahaha(a = 1000, b = 200);
begin
    if ifNumber(a) and ifNumber(b) then
    begin
        return a * b;
    end
    else
    begin
        importFile(ftXls(), "", "C:\test\testwbdata.xlsx", data);
        return data;
    end
end;
```

范例09：TSL 调用 OPS 服务函数

```tsl
url := "https://opi.tinysoft.com.cn/Service/Call/OPS/hahaha";
header := "Connection: keep-alive\r\nContent-Type: application/json\r\nJSON-Encode: gbk\r\nTS-EVENTNAME: wbdata";
ok := internetRequest(
    url,
    "",
    header,
    '{"a":1000,"b":9999}',
    "tuser",
    "tpassw",
    0,
    result,
    response_code,
    500000
);
echo "ok:", ok, " response_code:", response_code, " result:", result, "\r\n";
```

范例10：Python 调用 OPS 服务函数

```python
import requests
from requests.auth import HTTPBasicAuth

url = "https://opi.tinysoft.com.cn/Service/Call/OPS/hahaha"
headers = {
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "TS-EVENTNAME": "wbdata",
    "JSON-Encode": "gbk",
}
session = requests.Session()
session.auth = HTTPBasicAuth("tuser", "tpassw")
session.headers.update(headers)
response = session.post(url, json={"a": 1000, "b": 9999})
print(response.status_code)
print(response.text)
response.close()
```

范例11：TSL 订阅 OPS SSE 数据

```tsl
url := "https://opi.tinysoft.com.cn/Service/OPS/Subscription/time";
header := "Connection: keep-alive\r\nContent-Type: application/json\r\nJSON-Encode: gbk\r\nTS-EVENTNAME: wbdata\r\nAccept: text/event-stream";
session := createHttpSession();
setHttpMode(session, 1);
while true do
begin
    ok := internetRequest(
        session,
        url,
        "",
        header,
        "{}",
        "tuser",
        "tpassw",
        0,
        result,
        response_code,
        500000
    );
    echo "ok:", ok, " response_code:", response_code, " result:", result, "\r\n";
end;
```

范例12：Python 订阅 OPS SSE 数据

```python
import json
import requests

url = "https://opi.tinysoft.com.cn/Service/OPS/Subscription/time"
headers = {
    "Accept": "text/event-stream",
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "JSON-Encode": "gbk",
    "TS-EVENTNAME": "wbdata",
}
response = requests.post(
    url,
    headers=headers,
    data="{}",
    auth=("tuser", "tpassw"),
    stream=True,
    timeout=30,
)
for line in response.iter_lines(decode_unicode=True):
    if line and line.startswith("data:"):
        print(json.loads(line[5:].strip()))
```

范例13：JavaScript 与 TSL 日期互转

```javascript
function tslDateToJs(tslDate) {
    const daysFromTslEpochToUnixEpoch = 25569.0;
    const daysSinceUnixEpoch = tslDate - daysFromTslEpochToUnixEpoch;
    const millisecondsSinceUnixEpoch = daysSinceUnixEpoch * 24 * 60 * 60 * 1000;
    return new Date(millisecondsSinceUnixEpoch);
}

function jsDateToTsl(jsDate) {
    const millisecondsSinceUnixEpoch = jsDate.getTime();
    const daysSinceUnixEpoch = millisecondsSinceUnixEpoch / (24 * 60 * 60 * 1000);
    return daysSinceUnixEpoch + 25569.0;
}
```

范例14：Python 与 TSL 日期互转

```python
from datetime import datetime, timedelta

TSL_EPOCH = datetime(1899, 12, 30)

def tsl_date_to_py(value: float) -> datetime:
    return TSL_EPOCH + timedelta(days=value)

def py_date_to_tsl(value: datetime) -> float:
    return (value - TSL_EPOCH) / timedelta(days=1)
```
