、
Name
`。
如果创建使用通用协议插件支持交易所的实盘,在配置Settings
这个参数时,对于exchanges
属性可以使用如下设置:
{"eid": "Exchange", "label" : "test", "pair": "xxx", "meta" :{ ... , "Front" : "http://127.0.0.1:6666/XXX"}}
- 测试用策略:
- 策略参数
```Interval```
- ```JavaScript```策略代码
```javascript
function main(){
Sleep(6000)
Log(exchange.GetAccount())
Log("Interval:", Interval)
}
```
- 返回值:
// 成功创建实盘 { “code”: 0, “data”: { “result”: 74260, “error”: null } }
#### PluginRun
```PluginRun```,参数:```Settings```。使用扩展API接口调用**调试工具**功能。
调试工具页面地址:https://www.youquant.com/m/debug
- 参数
```Settings```为```JSON```对象类型,即调试工具中的设置(```Settings```配置中包括了测试代码写在```source```属性中)。
- 测试代码
```Python```范例:
```python
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import json
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
try:
import md5
import urllib2
from urllib import urlencode
except:
import hashlib as md5
import urllib.request as urllib2
from urllib.parse import urlencode
# API KEY已经打码,可用自己的API KEY测试
accessKey = 'f77XXXXXXXXXXXXXXX757'
# API KEY已经打码,可用自己的API KEY测试
secretKey = 'd8XXXXXXXXXXXXXXXX41ca97ea15'
def api(method, *args):
d = {
'version': '1.0',
'access_key': accessKey,
'method': method,
'args': json.dumps(list(args)),
'nonce': int(time.time() * 1000),
}
d['sign'] = md5.md5(('%s|%s|%s|%d|%s' % (d['version'], d['method'], d['args'], d['nonce'], secretKey)).encode('utf-8')).hexdigest()
# 注意: urllib2.urlopen 函数,超时问题,可以设置超时时间,urllib2.urlopen('https://www.youquant.com/api/v1', urlencode(d).encode('utf-8'), timeout=10) 设置超时 10秒
return json.loads(urllib2.urlopen('https://www.youquant.com/api/v1', urlencode(d).encode('utf-8')).read().decode('utf-8'))
# 返回托管者列表
code = '''
function main() {
Sleep(6000)
Log(exchange.GetAccount())
return exchanges[0].GetPosition()
}
'''
settings = {
# K线周期参数,60即为60秒
"period": 60,
"source": code,
# 托管者ID,可以指定在哪个托管者上运行实盘,如果该值为-1,代表自动分配
"node" : 12345,
"exchanges": [
{"pid": 1234, "pair": "FUTURES"},
{"pid": 1223, "pair": "FUTURES"}
]
}
print(api('PluginRun', settings))
注意:
{"pid": 1234, "pair": "FUTURES"}
{"pid": 1223, "pair": "FUTURES"}
对于settings中的exchanges
属性来说,在调用PluginRun
接口时只用设置一个(在调试工具页面使用时也只支持一个交易所对象)。在settings里设置2个交易所对象不会引起报错,但是在代码中如果访问第二个交易所对象就会报错。
api("PluginRun", settings)
返回结果:
{
'code': 0,
'data': {
'result': '
{
"logs":[
{...} // Log(exchange.GetAccount())
],
"result":"[]" // return exchanges[0].GetPosition()
}',
'error': None
}
}
- 参数
|参数名|类型|备注|
|-|-|-|
|robotId|为int类型|实盘ID|
**table Log**,查询数据库表Log的数据:
|参数名|类型|备注|
|-|-|-|
|logMinId|为int类型|Log日志的最小ID|
|logMaxId|为int类型|Log日志的最大ID|
|logOffset|为int类型|由logMinId和logMaxId确定范围后,根据logOffset偏移(跳过多少条记录),开始作为获取数据的起始位置。|
|logLimit|为int类型|确定起始位置后,选取的数据记录条数。|
**table Profit**,查询数据库表Profit的数据:
|参数名|类型|备注|
|-|-|-|
|profitMinId|为int类型|记录最小ID|
|profitMaxId|为int类型|记录最大ID|
|profitOffset|为int类型|偏移(跳过多少条记录),作为起始位置|
|profitLimit|为int类型|确定起始位置后,选取的数据记录条数。|
**table Chart**,查询数据表Chart的数据:
|参数名|类型|备注|
|-|-|-|
|chartMinId|为int类型|记录的最小ID|
|chartMaxId|为int类型|记录的最大ID|
|chartOffset|为int类型|偏移|
|chartLimit|为int类型|需要获取的记录条数|
|chartUpdateBaseId|为int类型|查询的更新后的基础ID|
|chartUpdateDate|为int类型|数据记录更新时间戳,会筛选出比这个时间戳大的记录|
**summaryLimit**,查询状态栏数据:
查询实盘的状态栏数据,该参数类型为整型,设置0表示不需要查询状态栏信息,设置为非0表示需要查询的状态栏信息字节数(该接口不限制数据量,可以指定一个较大的```summaryLimit```参数来获取所有状态栏信息)。状态栏数据储存在返回的数据的```summary```中。
```Python```范例:
```python
api('GetRobotLogs', 63024, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # 具体代码,参看以上内容:4、简单的例子,此处不再赘述,只写GetRobotLogs的调用和参数传入
返回值 返回数据:
{
'code': 0,
'data': {
'result': {
'chart': '',
'chartTime': 0,
'logs': [
{
'Total': 4,
'Max': 12,
'Min': 9,
'Arr': [
[12, 5, '', '', 0, 0, '[]', 1635495362912, '', ''],
[11, 3, 'Futures_Futu', '', 0, 0, 'Buy(1826.08, 1000): TrdMarket_CN: 缺少必要的参数: secMarket', 1635495362904, '', '']
]
},
{'Total': 0, 'Max': 0, 'Min': 0, 'Arr': []},
{'Total': 0, 'Max': 0, 'Min': 0, 'Arr': []}
],
'node_id': 507885,
'online': True,
'refresh': 0,
'status': 3,
'updateTime': 1635495362919,
'wd': 0
},
'error': None
}
}
数据库中的策略日志表
查询的日志截图:
以上返回结果数据中Arr
属性值描述:
'Arr': [
[12, 5, '', '', 0, 0, '[]', 1635495362912, '', ''],
[11, 3, 'Futures_Futu', '', 0, 0, 'Buy(1826.08, 1000): TrdMarket_CN: 缺少必要的参数: secMarket', 1635495362904, '', '']
]
|id|logType|eid|orderId|price|amount|extra|date|contractType|direction| |-|-|-|-|-|-|-|-|-|-| |12|5|“|”|0|0|‘[]’|1635495362912|“|”| |11|3|‘Futures_Futu’|“|0|0|‘Buy(1826.08, 1000): TrdMarket_CN: 缺少必要的参数: secMarket’|1635495362904|”|“|
```logType```值具体代表的日志类型:
|logType:|0|1|2|3|4|5|6|
|-|-|-|-|-|-|-|-|
|logType意义:|BUY|SALE|RETRACT|ERROR|PROFIT|MESSAGE|RESTART|
|中文意义|买单类型日志|卖单类型日志|撤销|错误|收益|日志|重启|
- 数据库中的收益图表日志表
该图表日志表数据与策略日志表中的收益日志一致。
“Arr”: [ [202, 2515.44, 1575896700315], [201, 1415.44, 1575896341568] ]
以其中一条日志数据为例:
[202, 2515.44, 1575896700315]
```202```为日志```ID```,```2515.44```为收益数值,```1575896700315```为时间戳。
- 数据库中的图表日志表
“Arr”: [ [23637, 0, “{\“close\”:648,\“high\”:650.5,\“low\”:647,\“open\”:650,\“x\”:1575960300000}“], [23636, 5, “{\“x\”:1575960300000,\“y\”:3.0735}“] ]
以其中一条日志数据为例:
[23637, 0, “{\“close\”:648,\“high\”:650.5,\“low\”:647,\“open\”:650,\“x\”:1575960300000}“],
```23637```为日志```ID```,```0```为图表数据系列索引,最后的数据```"{\"close\":648,\"high\":650.5,\"low\":647,\"open\":650,\"x\":1575960300000}"```为日志数据,这条数据为图表上的K线数据。
# 交易插件
### 简介
为了完善交易终端功能、更好的方便手动交易,推出了交易插件功能,位置如下:
![商品期货API文档(旧文档)](/upload/asset/1783fdaa5063f7e6410b9.png)
### 插件原理
原理和调试工具相同,发送一段代码到交易终端页面的托管者执行,并且支持返回图表和表格(调试工具目前也升级支持)。和**调试工具**功能相同只能执行3分钟,不收取费用。可实现一些简单的小功能,复杂的策略还是需要运行实盘。
### 插件编写
在新建策略页面,设置策略类型为:```交易插件```,交易插件支持```JavaScript```、```Python```、```C++```、```My语言```。
![商品期货API文档(旧文档)](/upload/asset/1784cc694b2122814b1da.png)
### 插件用途
插件可以执行代码一段时间,可执行一些简单的操作。例如**冰山委托**、**挂单**、**撤单**、**计算**等任务,和**调试工具**一样使用```return```返回结果,也可以直接返回图表和表格。下面举几个例子,其他功能可以自行探索。
- 返回深度的快照
```js
// 返回深度的快照
function main() {
var tbl = {
type: 'table',
title: '深度快照 @ ' + _D(),
cols: ['#', 'Amount', 'Ask', 'Bid', 'Amount'],
rows: []
}
var d = exchange.GetDepth()
for (var i = 0; i < Math.min(Math.min(d.Asks.length, d.Bids.length), 15); i++) {
tbl.rows.push([i, d.Asks[i].Amount, d.Asks[i].Price+'#ff0000', d.Bids[i].Price+'#0000ff', d.Bids[i].Amount])
}
return tbl
}
def main():
tbl = {
"type": "table",
"title": "深度快照 @ " + _D(),
"cols": ["#", "Amount", "Ask", "Bid", "Amount"],
"rows": []
}
d = exchange.GetDepth()
for i in range(min(min(len(d["Asks"]), len(d["Bids"])), 15)):
tbl["rows"].append([i, d["Asks"][i]["Amount"], str(d["Asks"][i]["Price"]) + "#FF0000", str(d["Bids"][i]["Price"]) + "#0000FF", d["Bids"][i]["Amount"]])
return tbl
void main() {
json tbl = R"({
"type": "table",
"title": "abc",
"cols": ["#", "Amount", "Ask", "Bid", "Amount"],
"rows": []
})"_json;
tbl["title"] = "深度快照 @" + _D();
auto d = exchange.GetDepth();
for(int i = 0; i < 5; i++) {
tbl["rows"].push_back({format("%d", i), format("%f", d.Asks[i].Amount), format("%f #FF0000", d.Asks[i].Price), format("%f #0000FF", d.Bids[i].Price), format("%f", d.Bids[i].Amount)});
}
LogStatus("`" + tbl.dump() + "`");
// C++ 不支持return json 显示表格,可以创建实盘显示状态栏表格
}
function main() { exchange.SetContractType(‘rb2205’) // 实际使用时,需要自行修改需要的合约代码 var recordsA = exchange.GetRecords(PERIOD_M5) exchange.SetContractType(‘rb2201’) // 实际使用时,需要自行修改需要的合约代码 var recordsB = exchange.GetRecords(PERIOD_M5)
for(var i = 0; i < Math.min(recordsA.length, recordsB.length); i++){
var diff = recordsA[recordsA.length - Math.min(recordsA.length, recordsB.length) + i].Close - recordsB[recordsB.length - Math.min(recordsA.length, recordsB.length) + i].Close
chart.series[0].data.push([recordsA[recordsA.length - Math.min(recordsA.length, recordsB.length) + i].Time, diff])
}
return chart
}
```python
chart = {
"__isStock": True,
"title": {"text": "差价分析图"},
"xAxis": {"type": "datetime"},
"yAxis": {
"title": {"text": "差价"},
"opposite": False
},
"series": [
{"name": "diff", "data": []}
]
}
def main():
exchange.SetContractType("rb2205")
recordsA = exchange.GetRecords(PERIOD_M5)
exchange.SetContractType("rb2201")
recordsB = exchange.GetRecords(PERIOD_M5)
for i in range(min(len(recordsA), len(recordsB))):
diff = recordsA[len(recordsA) - min(len(recordsA), len(recordsB)) + i].Close - recordsB[len(recordsB) - min(len(recordsA), len(recordsB)) + i].Close
chart["series"][0]["data"].append([recordsA[len(recordsA) - min(len(recordsA), len(recordsB)) + i]["Time"], diff])
return chart
// C++ 不支持 return json 结构画图
策略广场中还有其它范例。
分析公式参考了worldquant
公开的alpha101
:http://q.youquant.com/chart/doc/101_Formulaic_Alphas.pdf 中行情计算的方法,基本兼容了其语法(未实现的有说明),并进行了增强。
用于快速对时间序列进行运算,验证想法,使用地址。
页面简介:
下面的“{}”代表占位符,所有表达式大小写不敏感,x代表数据时间序列
abs(x), log(x), sign(x)
字面意思,分别是绝对值、对数、符号函数。以下操作符+, -, *, /, >, <
也符合其标准的含义,==
:是否相等,||
:逻辑或,x ? y : z
:三目运算符。
rank(x)
:横截面的排序,返回所在百分比。需要指定侯选多个标的池,用于单个行情无法计算,将直接返回原结果。delay(x, d)
: 序列d周期前的值。sma(x, d)
: 序列d周期的简单均线。correlation(x, y, d)
:时间序列x和y过去d周期的相关系数。covariance(x, y, d)
:时间序列x和y过去d周期的协方差。scale(x, a)
:归一化数据,使sum(abs(x))=a
(a默认为1)。delta(x, d)
:时间序列x的现在值减去d周期前的值。signedpower(x, a)
: x^a
。decay_linear(x, d)
:时间序列x带权重的d周期移动平均值,权重为d,d-1,d-2….1(经过归一化处理)。indneutralize(x, g)
: 针对行业分类g进行中性处理,目前不支持。ts_{O}(x, d)
: 对时间序列x过去d个周期进行O操作(O可具体代表min、max等,接下来有介绍),d会转为整数。ts_min(x, d)
: 过去d周期最小值。ts_max(x, d)
: 过去d周期最大值。ts_argmax(x, d)
: ts_max(x, d)
位置。ts_argmin(x, d)
: ts_min(x, d)
位置。ts_rank(x, d)
: 过去d个周期时间序列x值的排序(百分比排序)。min(x, d)
: ts_min(x, d)
。max(x, d)
: ts_max(x, d)
。sum(x, d)
:过去d周期的和。product(x, d)
:过去d周期的积。stddev(x, d)
:过去d周期的标准差。输入数据的大小写不敏感,默认的数据是网页上的选择品种,也可以直接指定例如MA888.close
returns
:收盘价收益率。open, close, high, low, volume
:周期内开盘价、收盘价、最高价、最低价、成交量。vwap
:成交量加权成交价,未实现,当前为收盘价。cap
:总市值,未实现。IndClass
:行业分类,未实现。支持一次输出多个结果,用列表表示。例如[sma(close, 10), sma(high, 30)]
将会在图中画两条线。除了输入时间序列数据外,也可以当成一个简单的计算器。
优宽量化交易平台提供模块化、定制化的交易终端页面。可以自由添加各种数据模块、交易功能模块,甚至可以自己编写代码开发模块(交易终端插件)。凭借着高度灵活自由的使用方式也极大方便了手动交易、半程序化交易的用户。 交易终端页面上的各种模块均可以拖动、缩放,可以修改模块绑定的交易对、交易所等设置,可以添加多个同类型的模块。
调试工具页面提供了一个快速实盘测试代码的环境,目前仅支持JavaScript
语言。
支持本地编辑器远程同步策略代码到优宽量化交易平台,支持Sublime Text
/Atom
/Vim
/VSCode
编辑器。在策略编辑页面点击「远程编辑」展开插件下载地址按钮,显示当前策略的远程同步密钥(token)。
点击「更新密钥」可以刷新当前密钥显示,点击「删除密钥」可以删除当前策略的密钥(token)。
不同编辑器的插件安装方式略有差别,可以点击下载按钮跳转到具体的远程同步插件项目。
运行实盘时需要保存实盘配置的参数数据可以点击「导出参数」按钮。导出的策略参数将以json
文件保存,导出的策略参数配置也可以再次导入实盘,点击「导入参数」按钮即可把保存的策略实盘参数导入到当前实盘,导入后点击「更新参数」保存。
下载源码
导出策略源码,导出的文件类型基于策略的编程语言。JavaScript策略导出扩展名为js
的文件;python策略导出扩展名为py
的文件;c++策略导出扩展名为cpp
的文件;麦语言策略导出扩展名为txt
的文件。注意只导出策略源码,不包含策略参数、模板引用等信息。
导出策略
导出完整策略,包含策略源码、参数设计等策略所有信息,导出的文件为xml
文件。
导入策略
使用「导出策略」功能导出的xml
文件,在策略编辑页面点击「导入策略」按钮选中需要导入的xml
文件即可导入完整策略。导入后需要点击「保存」按钮保存策略。
策略名称,策略参数的描述,都可以用中文|英文
的形式书写,让网页自动识别语言显示。
其它地方,例如:策略描述,使用说明等这些Markdown
格式的文本,用[trans]中文|英文[/trans]
或者[trans]中文||英文[/trans]
也可以达到自动识别的效果,以上例子的效果如下图所示:
中文页面显示:
英文页面显示:
切换语言后,刷新网页后生效。
在策略代码中可以写入字符串的函数也支持语言切换,例如Log
函数、LogStatus
函数等。
function main() {
Log("[trans]日志|log[/trans]")
var table = {
type: "table",
title: "[trans]操作|option[/trans]",
cols: ["[trans]列1|col1[/trans]", "[trans]列2|col2[/trans]", "[trans]操作|option[/trans]"],
rows: [
["[trans]螺纹钢主力合约|rb888[/trans]", "[trans]甲醇主力合约|MA888[/trans]", {"type": "button", "cmd": "coverAll", "name": "平仓|cover", "description": "描述|description"}] // 注意:按钮中不用加[trans]标签
]
}
LogStatus("[trans]信息|message[/trans]", "\n`" + JSON.stringify(table) + "`")
throw "[trans]错误|error[/trans]"
}
import json
def main():
Log("[trans]日志|log[/trans]")
table = {
"type": "table",
"title": "[trans]操作|option[/trans]",
"cols": ["[trans]列1|col1[/trans]", "[trans]列2|col2[/trans]", "[trans]操作|option[/trans]"],
"rows": [
["[trans]螺纹钢主力合约|rb888[/trans]", "[trans]甲醇主力合约|MA888[/trans]", {"type": "button", "cmd": "coverAll", "name": "平仓|cover", "description": "描述|description"}]
]
}
LogStatus("[trans]信息|message[/trans]", "\n`" + json.dumps(table) + "`")
raise Exception("[trans]错误|error[/trans]")
void main() {
Log("[trans]日志|log[/trans]");
json table = R"({
"type": "table",
"title": "[trans]操作|option[/trans]",
"cols": ["[trans]列1|col1[/trans]", "[trans]列2|col2[/trans]", "[trans]操作|option[/trans]"],
"rows": [
["[trans]螺纹钢主力合约|rb888[/trans]", "[trans]甲醇主力合约|MA888[/trans]", {"type": "button", "cmd": "coverAll", "name": "平仓|cover", "description": "描述|description"}]
]
})"_json;
LogStatus("[trans]信息|message[/trans]", "\n`" + table.dump() + "`");
Panic("[trans]错误|error[/trans]");
}
下载托管者软件之后,解压缩后的可执行文件,文件名robot
即为托管者程序,在部署托管者时可以给托管者程序指定参数。
-v
:查看当前托管者程序的版本、编译时间等信息。
完整的执行命令以苹果电脑Mac系统
为例:./robot -v
。-s
:运行托管者程序时指定的和优宽量化交易平台通信的地址。
完整的执行命令以苹果电脑Mac系统
为例:./robot -s node.youquant.com/xxxxxxx
,xxxxxxx
部分为每个优宽量化交易平台账号唯一的识别ID,命令执行后会提示要求输入对应的优宽量化交易平台账号的密码。-p
:可以直接在运行命令中指定参数输入密码,不建议这样做,因为会留下密码参数在当前系统记录中。假设地址node.youquant.com/xxxxxxx
对应的账号密码为:abc123456
。
完整的执行命令以苹果电脑Mac系统
为例:./robot -s node.youquant.com/xxxxxxx -p abc123456
。-n
:给运行的托管者程序附加标签信息。
完整的执行命令以苹果电脑Mac系统
为例:./robot -n macTest -s node.youquant.com/xxxxxxx
。在平台托管者管理页面的托管者信息中会有macTest
文本标记。-l
:打印当前托管者支持的交易所列表。
完整的执行命令以苹果电脑Mac系统
为例:./robot -l
。即可输出所支持的交易所名称。exchange.Go
函数,操作时没有合理wait
等待协程结束,导致协程数量过大。Decrypt: Secret key decrypt failed
错误,该错误会导致实盘无法启动。错误原因是修改了优宽量化交易平台的账号密码导致所有配置的API KEY
失效,需要重新配置API KEY
,重启托管者即可。ValueError: bad marshal data (unknown type code)
,将策略运行的Python环境升级或者安装为:Python 2.7
、Python 3.5
、Python 3.6
其中之一的策略支持的版本即可。interrupt
错误,该错误是由于程序在执行某个操作(例如访问交易所接口)时,用户点击了实盘页面上的停止实盘按钮,实盘停止中断了当前的操作打印的报错信息。该报错并没有什么影响,仅仅是一个日志记录。在优宽量化交易平台「实盘」页面、「策略库」页面可以点击右侧分组管理按钮,用来给策略、实盘分组管理。例如对于策略的分组管理时可以把模板类库分为一组、JavaScript语言的策略分为一组、测试用策略分为一组。
子账号 登录平台后,点击「控制中心」、「账号设置」跳转到优宽账户管理页面。点击「子账户组」可以看到子账户创建页面,操作权限控件内选择所创建子账号可以访问的实盘,用户信息控件内设置子账号用户名、子账号登录密码。点击「创建子账户」按钮即可创建一个子账号。创建后的子账号会在当前页面显示、并且可以「修改」、「锁定/解锁」、「删除」。
子账号只有有限权限,只能看到操作权限设置中授权的实盘。对于授权的实盘拥有修改参数、停止实盘、重启实盘的权限,但是无法修改实盘配置的交易所对象。子账号的使用场景通常为: - A.量化团队管理多个实盘策略时方便登录、管理。 - B.策略租用时的调试。
实盘围观 在优宽平台实盘页面的实盘列表中点击「公开」按钮即可公开展示当前行的实盘。实盘围观目前有两种方式: - 1、在优宽平台公开的实盘围观页面展示实盘。当点击「公开」按钮后选择公开分享即可。 - 2、创建围观私链。 当点击「公开」按钮后选择内部分享,设置有效期后即可生成一个私有链接用来登录该策略实盘的私有围观页面。
在策略库页面,策略右侧的「操作项」按钮点击后弹出的菜单中有分享、出租操作选项。
策略分享 - 公开分享 点击「分享」按钮后会弹出对话框,可以选择「公开分享」。策略即完整的分享在平台的策略广场,任何用户都可以复制该策略。
策略出租 - 公开出售 点击「出租」按钮后会弹出对话框,可以选择「公开出售」。策略即可申请上架(需要通过审核)。
重要提示,在创建、分发策略注册码时请务必仔细确认是「注册码」还是「复制码」。以免误将策略分享出去。
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays) {
// force by days
period = 86400000
if (profits.length == 0) {
return null
}
var freeProfit = 0.03 // 0.04
var yearRange = yearDays * 86400000
var totalReturns = profits[profits.length - 1][1] / totalAssets
var annualizedReturns = (totalReturns * yearRange) / (te - ts)
// MaxDrawDown
var maxDrawdown = 0
var maxAssets = totalAssets
var maxAssetsTime = 0
var maxDrawdownTime = 0
var maxDrawdownStartTime = 0
var winningRate = 0
var winningResult = 0
for (var i = 0; i < profits.length; i++) {
if (i == 0) {
if (profits[i][1] > 0) {
winningResult++
}
} else {
if (profits[i][1] > profits[i - 1][1]) {
winningResult++
}
}
if ((profits[i][1] + totalAssets) > maxAssets) {
maxAssets = profits[i][1] + totalAssets
maxAssetsTime = profits[i][0]
}
if (maxAssets > 0) {
var drawDown = 1 - (profits[i][1] + totalAssets) / maxAssets
if (drawDown > maxDrawdown) {
maxDrawdown = drawDown
maxDrawdownTime = profits[i][0]
maxDrawdownStartTime = maxAssetsTime
}
}
}
if (profits.length > 0) {
winningRate = winningResult / profits.length
}
// trim profits
var i = 0
var datas = []
var sum = 0
var preProfit = 0
var perRatio = 0
var rangeEnd = te
if ((te - ts) % period > 0) {
rangeEnd = (parseInt(te / period) + 1) * period
}
for (var n = ts; n < rangeEnd; n += period) {
var dayProfit = 0.0
var cut = n + period
while (i < profits.length && profits[i][0] < cut) {
dayProfit += (profits[i][1] - preProfit)
preProfit = profits[i][1]
i++
}
perRatio = ((dayProfit / totalAssets) * yearRange) / period
sum += perRatio
datas.push(perRatio)
}
var sharpeRatio = 0
var volatility = 0
if (datas.length > 0) {
var avg = sum / datas.length;
var std = 0;
for (i = 0; i < datas.length; i++) {
std += Math.pow(datas[i] - avg, 2);
}
volatility = Math.sqrt(std / datas.length);
if (volatility !== 0) {
sharpeRatio = (annualizedReturns - freeProfit) / volatility
}
}
return {
totalAssets: totalAssets,
yearDays: yearDays,
totalReturns: totalReturns,
annualizedReturns: annualizedReturns,
sharpeRatio: sharpeRatio,
volatility: volatility,
maxDrawdown: maxDrawdown,
maxDrawdownTime: maxDrawdownTime,
maxAssetsTime: maxAssetsTime,
maxDrawdownStartTime: maxDrawdownStartTime,
winningRate: winningRate
}
}
henryp1 怎么不显示目录?
雨幕(youquant) 哪个目录 ?