forked from fmzquant/strategies
-
Notifications
You must be signed in to change notification settings - Fork 1
/
**********价值平均定投策略**********.js
262 lines (221 loc) · 8.86 KB
/
**********价值平均定投策略**********.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
策略出处: https://www.botvs.com/strategy/8602
策略名称: **********价值平均定投策略**********
策略作者: Lizza
策略描述:
实盘:https://www.botvs.com/m/robot/26018
这个策略适合长期看好比特币的脑残粉,使用价值平均策略来进行定投,可以有效的抵抗市场波动。(关于价值平均定投请度娘。)
基本的思路是先想好每个月想要投入多少钱(策略变量:MoneyEveryMonth),然后决定多久交易一次,交易的间隔不建议小于5分钟(策略参数:InvestInternal)。
以下用一个实例说明策略思路和买卖时机:
假设每月想要买入价值72000元人民币的比特币(便于计算),每个小时交易一次,就是计划每个月交易24*30=720次,每次计划投入的资金价值为72000/720=100元(变量A)。
小时B,当时价格C,已投入资金D,已买入币数E,现在币价值F,本次投入资金G, 本次买入币数H
1 400 0 0 C*E=0 A*B-F=100 G/C=0.25
2 200 100 0.25 200*0.25=50 100*2-50=150 0.75
3 1000 250 1 1000 100*3-1000=-700 -0.7
4 500 -550 0.3 150 100*4-150=250 0.5
最终的结果,投入资金300,买入0.8个比特币(价值400元),平均价格375元。
说明:程序会每次检查账户内的资金和比特币与启动时的差额,以此计算每次需要购买的数量,因此不要用其他机器人公用一个帐户,也不要手工进行买入卖出的操作。如果在交易所有充值和体现,应该在程序互动部分填入,否则程序计算会错误。
参数 默认值 描述
--------------- ------- ------------
ErrorInterval 2000 出错重试(毫秒)
InvestInternal 15 投资间隔(按照分钟计算)
MoneyEveryMonth 5000 每月要投资的资金量
SlidePrice 0.05 购买时滑点
按钮 默认值 描述
----------- ---------- -----------
Pause __button__ 暂停交易
Continue __button__ 继续交易
MoneyChange false 纪录资金充值或提现
StockChange false 纪录数字货币充值或提现
*/
var initAccount;
var startTime; //unxi timestamp
var pause = false; //pause execution of strategy or continue
var moneyDeposit = 0; // positive means deposit, negative means withdraw
var sotckDeposit = 0; // positive means deposit, negative means withdraw
function AdjustFloat(v) {
return Math.floor(v * 1000)/1000;
}
function GetAccount() {
var account = null;
while (!(account = exchange.GetAccount())) {
Log('Get Account Error');
Sleep(ErrorInterval);
}
return account;
}
function GetCurrentPrice() {
var ticker = null;
while (!(ticker = exchange.GetTicker())) {
Log('Get Ticker Error');
Sleep(ErrorInterval);
}
return AdjustFloat(ticker.Last);
}
function GetOrders(){
var orders = null;
while (!(orders = exchange.GetOrders())) {
Log('Get Orders Error');
Sleep(ErrorInterval);
}
return orders;
}
function CancelPendingOrders() {
while(true){
var orders = GetOrders();
if (orders.length === 0) {
return;
}
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
if (i < (orders.length-1)) {
Sleep(ErrorInterval);
}
}
}
}
function ProcessCommand() {
var command = GetCommand();
if (command !== null) {
Log('command:', command);
if (command === 'pause') {
pause = true;
}
if (command === 'Continue') {
pause = false;
}
if(command.indexOf('MoneyChange:') === 0){
moneyDeposit = parseFloat(command.replace("MoneyChange:", ""));
Log('Deposit Money:', moneyDeposit);
}
if(command.indexOf('StockChange:') === 0){
stockDeposit = parseFloat(command.replace("StockChange:", ""));
Log('Deposit Stock:',stockDeposit);
}
}
}
function CaculateMoneyToInvest(currentPrice,investCount)
{
var moneyEveryInvest = MoneyEveryMonth * InvestInternal / (30 * 24 * 60);
var totalStockInvested = 0.0;
var totalMoneyInvested = 0.0;
var totalValueInvested = 0.0;
var moneyToInvestThisTime = 0.0;
CancelPendingOrders();
var accountNow = GetAccount();
totalMoneyInvested = initAccount.Balance + initAccount.FrozenBalance + moneyDeposit - accountNow.Balance - accountNow.FrozenBalance;
totalStockInvested = accountNow.Stocks + accountNow.FrozenStocks - initAccount.Stocks - initAccount.FrozenStocks - stockDeposit;
Log('Total Money Invested:',totalMoneyInvested);
Log('Total Stock Invested:',totalStockInvested);
totalValueInvested = AdjustFloat(totalStockInvested * currentPrice);
Log('Total Value Invested:',totalValueInvested);
var averagePrice = 0;
if(totalStockInvested !== 0){
averagePrice = AdjustFloat(totalMoneyInvested / totalStockInvested);
//Log('Average Price:', AdjustFloat(totalMoneyInvested / totalStockInvested),'#ff0000@');
}
moneyToInvestThisTime = AdjustFloat(moneyEveryInvest * investCount - totalValueInvested);
Log('Money to Invest This Time:', moneyToInvestThisTime);
var profit = totalValueInvested - totalMoneyInvested;
LogStatus('Count:',investCount,' Money:', totalMoneyInvested, 'Stock:', totalStockInvested, 'Average:', averagePrice,'Profit:',profit);
Log('Count:',investCount,' Money:', totalMoneyInvested, 'Stock:', totalStockInvested, 'Average:', averagePrice,'Profit:',profit,'#ff0000@');
LogProfit(profit);
return moneyToInvestThisTime;
}
function onTick(investCount) {
var currentPrice = GetCurrentPrice();
Log('Current Price', currentPrice);
var moneyToInvestThisTime = CaculateMoneyToInvest(currentPrice,investCount);
var stockToInvestThisTime = 0;
if(moneyToInvestThisTime > 0){ //Buy
stockToInvestThisTime = AdjustFloat(moneyToInvestThisTime / (currentPrice + SlidePrice));
}else{ //Sell
stockToInvestThisTime = AdjustFloat(moneyToInvestThisTime / (currentPrice - SlidePrice));
}
var minPrice = exchange.GetMinPrice();
if(Math.abs(moneyToInvestThisTime) < minPrice){
Log('Invest Less Than MinPrice:', minPrice);
return;
}
var minStock = exchange.GetMinStock();
if(Math.abs(stockToInvestThisTime) < minStock){
Log('Invest Less Than MinStock:',minStock);
return;
}
var account = GetAccount();
if(stockToInvestThisTime > 0){ //Buy
if(account.Balance < moneyToInvestThisTime){
Log('Money not Enough.#ff0000@');
return;
}
}else{ //Sell
if(account.Stocks < Math.abs(stockToInvestThisTime)){
Log('Stock not Enough.#ff0000@');
return;
}
}
var orderID = -1;
if(stockToInvestThisTime > 0){ //Buy
Log('Buy Stock:',stockToInvestThisTime);
orderID = exchange.Buy(currentPrice + SlidePrice,stockToInvestThisTime);
}
if(stockToInvestThisTime < 0){ //Sell
Log('Sell Stock:',Math.abs(stockToInvestThisTime));
orderID = exchange.Sell(currentPrice - SlidePrice,Math.abs(stockToInvestThisTime));
}
}
function main() {
EnableLogLocal(true);
SetFailover(true);
exchange.IO("websocket");
initAccount = GetAccount();
//Log(exchange.GetName(), exchange.GetCurrency(), initAccount);
startTime = _G('StartTime');
if(startTime === null){
startTime = new Date().getTime();
_G('StartTime',startTime);
Log('Set Start Time:', startTime);
}else{
Log('Read Start Time',new Date().setTime(startTime));
}
var investCount = _G('InvestCount' );
if(investCount === null){
investCount = 1;
Log('Set Invest Starting from Count 1.');
}
else{
Log('Invest Continuing from:', investCount);
}
moneyDeposit = _G('MoneyDeposit');
if(moneyDeposit === null){
moneyDeposit = 0;
Log('Set Money Deposit 0.');
}
else{
Log('Read Money Deposit:', moneyDeposit);
}
stockDeposit = _G('StockDeposit');
if(stockDeposit === null){
stockDeposit = 0;
Log('Set Stock Deposit 0.');
}
else{
Log('Read Stock Deposit:', stockDeposit);
}
while (true) {
ProcessCommand();
if (!pause) {
Log('=================================================');
Log('Invest Count', investCount);
onTick(investCount);
investCount += 1;
_G('InvestCount',investCount);
}
Sleep(InvestInternal * 1000 * 60);
}
}
function onexit(){
_G('MoneyDeposit',moneyDeposit);
_G('StockDeposit', stockDeposit);
Log('Robot Stopped!#ff0000@');
}