backend: slope support, gui:add json
This commit is contained in:
15
testy/testSlope.py
Normal file
15
testy/testSlope.py
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
sma = list
|
||||
|
||||
sma = [28.90, 28.91, 28.91, 28.92, 28.97, 28.99]
|
||||
slope_lookback = 4
|
||||
roc_lookback = 4
|
||||
|
||||
slope = (sma[-1] - sma[-slope_lookback])/slope_lookback
|
||||
roc = ((sma[-1] - sma[-roc_lookback])/sma[-roc_lookback])*100
|
||||
|
||||
print(slope)
|
||||
|
||||
|
||||
# -1 až 0 klesání
|
||||
# 0 až 1 stoupání
|
||||
3
testy/testTelegram.py
Normal file
3
testy/testTelegram.py
Normal file
@ -0,0 +1,3 @@
|
||||
from v2realbot.utils.utils import send_to_telegram
|
||||
|
||||
send_to_telegram("nazdarek")
|
||||
@ -45,7 +45,10 @@ stratvars = AttributeDict(maxpozic = 250,
|
||||
curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01],
|
||||
blockbuy = 0,
|
||||
ticks2reset = 0.04,
|
||||
consolidation_bar_count = 10)
|
||||
consolidation_bar_count = 10,
|
||||
slope_lookback = 20,
|
||||
minimum_slope = -0.23
|
||||
)
|
||||
##toto rozparsovat a strategii spustit stejne jako v main
|
||||
toml_string = """
|
||||
[[strategies]]
|
||||
@ -106,7 +109,7 @@ def next(data, state: StrategyState):
|
||||
price = last_price
|
||||
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
|
||||
state.buy_l(price=price, size=qty)
|
||||
print("prvni limitka na aktuální cenu. Další podle křicvky", price, qty)
|
||||
print("prvni limitka na aktuální cenu. Další podle křivky", price, qty)
|
||||
for i in range(0,vykladka-1):
|
||||
price = price2dec(float(price - curve[i]))
|
||||
if price == last_price:
|
||||
@ -133,24 +136,55 @@ def next(data, state: StrategyState):
|
||||
return 0
|
||||
|
||||
try:
|
||||
|
||||
## slope vyresi rychlé sesupy - jeste je treba podchytit pomalejsi sesupy
|
||||
|
||||
|
||||
slope = 99
|
||||
#minimum slope disabled if -1
|
||||
|
||||
|
||||
#roc_lookback = 20
|
||||
#print(state.vars.MA, "MACKO")
|
||||
#print(state.bars.hlcc4)
|
||||
state.indicators.ema = ema(state.bars.close, state.vars.MA) #state.bars.vwap
|
||||
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
|
||||
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
|
||||
ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
|
||||
|
||||
slope_lookback = int(state.vars.slope_lookback)
|
||||
minimum_slope = float(state.vars.minimum_slope)
|
||||
|
||||
if len(state.bars.close) > slope_lookback:
|
||||
#slope = ((state.indicators.ema[-1] - state.indicators.ema[-slope_lookback])/slope_lookback)*100
|
||||
#PUVODNI slope = ((state.bars.close[-1] - state.bars.close[-slope_lookback])/slope_lookback)*100
|
||||
slope = ((state.bars.close[-1] - state.bars.close[-slope_lookback])/state.bars.close[-slope_lookback])*100
|
||||
#roc = ((state.indicators.ema[-1] - state.indicators.ema[-roc_lookback])/state.indicators.ema[-roc_lookback])*100
|
||||
state.indicators.slope.append(slope)
|
||||
#state.indicators.roc.append(roc)
|
||||
ic(state.indicators.slope[-5:])
|
||||
#ic(state.indicators.roc[-5:])
|
||||
except Exception as e:
|
||||
print("No data for MA yet", str(e))
|
||||
print("Exception in NEXT Indicator section", str(e))
|
||||
|
||||
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
|
||||
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
|
||||
|
||||
#and data['index'] > state.vars.lastbuyindex+state.vars.Trend:
|
||||
#neni vylozeno muzeme nakupovat
|
||||
#SLOPE ANGLE PROTECTION
|
||||
if slope < minimum_slope:
|
||||
print("OCHRANA SLOPE TOO HIGH")
|
||||
if len(state.vars.pendingbuys)>0:
|
||||
print("CANCEL PENDINGBUYS")
|
||||
ic(state.vars.pendingbuys)
|
||||
res = asyncio.run(state.cancel_pending_buys())
|
||||
ic(state.vars.pendingbuys)
|
||||
print("slope", slope)
|
||||
print("min slope", minimum_slope)
|
||||
|
||||
if ic(state.vars.jevylozeno) == 0:
|
||||
print("Neni vylozeno, muzeme testovat nakup")
|
||||
|
||||
if isfalling(state.indicators.ema,state.vars.Trend):
|
||||
if isfalling(state.indicators.ema,state.vars.Trend) and slope > minimum_slope:
|
||||
print("BUY MARKET")
|
||||
ic(data['updated'])
|
||||
ic(state.time)
|
||||
@ -167,7 +201,7 @@ def next(data, state: StrategyState):
|
||||
#TODO predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
|
||||
#TODO spoustet 1x za X iteraci nebo cas
|
||||
if state.vars.jevylozeno == 1:
|
||||
#pokud mame vylozeno a cena je vetsi nez 0.04
|
||||
#pokud mame vylozeno a cena je vetsi nez tick2reset
|
||||
if len(state.vars.pendingbuys)>0:
|
||||
maxprice = max(state.vars.pendingbuys.values())
|
||||
print("max cena v orderbuys", maxprice)
|
||||
@ -264,6 +298,8 @@ def init(state: StrategyState):
|
||||
#place to declare new vars
|
||||
print("INIT v main",state.name)
|
||||
state.indicators['ema'] = []
|
||||
state.indicators['slope'] = []
|
||||
#state.indicators['roc'] = []
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
Binary file not shown.
@ -517,7 +517,7 @@ class Backtester:
|
||||
#with lock:
|
||||
for o in self.open_orders:
|
||||
#print(o)
|
||||
if o.symbol == symbol:
|
||||
if o.symbol == symbol and o.canceled_at is None:
|
||||
if side is None or o.side == side:
|
||||
res.append(o)
|
||||
return res
|
||||
|
||||
@ -235,6 +235,7 @@ def capsule(target: object, db: object):
|
||||
reason = "SHUTDOWN OK"
|
||||
except Exception as e:
|
||||
reason = "SHUTDOWN Exception:" + str(e)
|
||||
print(str(e))
|
||||
print(reason)
|
||||
finally:
|
||||
# remove runners after thread is stopped and save results to stratin history
|
||||
|
||||
Binary file not shown.
@ -147,7 +147,7 @@ class LiveInterface(GeneralInterface):
|
||||
return a
|
||||
except APIError as e:
|
||||
#order doesnt exist
|
||||
if e.code == 40410000: return 0,0
|
||||
if e.code == 40410000: return 0
|
||||
else:
|
||||
print("nepovedlo se zrusit objednavku", str(e))
|
||||
#raise Exception(e)
|
||||
|
||||
@ -11,7 +11,7 @@ from fastapi import FastAPI, Depends, HTTPException, status
|
||||
from fastapi.security import APIKeyHeader
|
||||
import uvicorn
|
||||
from uuid import UUID
|
||||
import controller.services as cs
|
||||
import v2realbot.controller.services as cs
|
||||
from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest
|
||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query
|
||||
from fastapi.responses import HTMLResponse, FileResponse
|
||||
|
||||
@ -79,7 +79,13 @@
|
||||
</div>
|
||||
<div id="stratin-table" class="flex-items">
|
||||
<div id="stratin-table">
|
||||
<button id="button_add" class="btn btn-success">Add</button><button id="button_edit" class="btn btn-success">Edit</button><button id="button_dup" class="btn btn-success">Duplicate</button><button id="button_delete" class="btn btn-success">Delete</button><button id="button_run" class="btn btn-success">Run Strategy</button>
|
||||
<button id="button_add" class="btn btn-success">Add</button>
|
||||
<button id="button_add_json" class="btn btn-success">Add JSON</button>
|
||||
<button id="button_edit" class="btn btn-success">Edit</button>
|
||||
<button id="button_dup" class="btn btn-success">Duplicate</button>
|
||||
<button id="button_copy" class="btn btn-success">Copy JSON</button>
|
||||
<button id="button_delete" class="btn btn-success">Delete</button>
|
||||
<button id="button_run" class="btn btn-success">Run Strategy</button>
|
||||
<table id="stratinTable" class="display" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -192,6 +198,28 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="jsonModal" class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<form method="post" id="jsonForm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title_json"><i class="fa fa-plus"></i> Add JSON Record</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="jsontext" class="control-label">JSON</label>
|
||||
<textarea class="form-control" rows="7" id="jsontext" name="jsontext" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="submit" name="json_add" id="json_add" class="btn btn-info" value="Add" />
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="runModal" class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<form method="post" id="runForm">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//const chartOptions = { layout: { textColor: 'black', background: { type: 'solid', color: 'white' } } };
|
||||
const chartOptions = { width: 1200, height: 600}
|
||||
const chartOptions = { width: 1200, height: 600, leftPriceScale: {visible: true}}
|
||||
const chart = LightweightCharts.createChart(document.getElementById('chart'), chartOptions);
|
||||
chart.applyOptions({ timeScale: { visible: true, timeVisible: true, secondsVisible: true }, crosshair: {
|
||||
mode: LightweightCharts.CrosshairMode.Normal, labelVisible: true
|
||||
|
||||
@ -64,6 +64,7 @@ $(document).ready(function () {
|
||||
$('#button_stop').attr('disabled','disabled');
|
||||
$('#button_edit').attr('disabled','disabled');
|
||||
$('#button_dup').attr('disabled','disabled');
|
||||
$('#button_copy').attr('disabled','disabled');
|
||||
$('#button_delete').attr('disabled','disabled');
|
||||
$('#button_run').attr('disabled','disabled');
|
||||
|
||||
@ -72,6 +73,7 @@ $(document).ready(function () {
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
$('#button_dup').attr('disabled','disabled');
|
||||
$('#button_copy').attr('disabled','disabled');
|
||||
$('#button_edit').attr('disabled','disabled');
|
||||
$('#button_delete').attr('disabled','disabled');
|
||||
$('#button_run').attr('disabled','disabled');
|
||||
@ -79,6 +81,7 @@ $(document).ready(function () {
|
||||
stratinRecords.$('tr.selected').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
$('#button_dup').attr('disabled',false);
|
||||
$('#button_copy').attr('disabled',false);
|
||||
$('#button_edit').attr('disabled',false);
|
||||
$('#button_delete').attr('disabled',false);
|
||||
$('#button_run').attr('disabled',false);
|
||||
@ -105,6 +108,28 @@ $(document).ready(function () {
|
||||
stratinRecords.ajax.reload();
|
||||
})
|
||||
|
||||
//button refresh
|
||||
$('#button_copy').click(function () {
|
||||
event.preventDefault();
|
||||
$('#button_copy').attr('disabled','disabled');
|
||||
row = stratinRecords.row('.selected').data();
|
||||
const rec = new Object()
|
||||
rec.id2 = parseInt(row.id2);
|
||||
rec.name = row.name;
|
||||
rec.symbol = row.symbol;
|
||||
rec.class_name = row.class_name;
|
||||
rec.script = row.script;
|
||||
rec.open_rush = row.open_rush;
|
||||
rec.close_rush = row.close_rush;
|
||||
rec.stratvars_conf = row.stratvars_conf;
|
||||
rec.add_data_conf = row.add_data_conf;
|
||||
rec.note = row.note;
|
||||
rec.history = "";
|
||||
jsonString = JSON.stringify(rec);
|
||||
navigator.clipboard.writeText(jsonString);
|
||||
$('#button_copy').attr('disabled', false);
|
||||
})
|
||||
|
||||
//button duplicate
|
||||
$('#button_dup').click(function () {
|
||||
row = stratinRecords.row('.selected').data();
|
||||
@ -250,6 +275,7 @@ $(document).ready(function () {
|
||||
$('#action').val('addRecord');
|
||||
$('#save').val('Add');
|
||||
});
|
||||
|
||||
//edit button
|
||||
$('#button_edit').click(function () {
|
||||
row = stratinRecords.row('.selected').data();
|
||||
@ -279,6 +305,10 @@ $(document).ready(function () {
|
||||
$('#save').val('Delete');
|
||||
|
||||
});
|
||||
//json add button
|
||||
$('#button_add_json').click(function () {
|
||||
window.$('#jsonModal').modal('show');
|
||||
});
|
||||
} );
|
||||
|
||||
//stratin table
|
||||
@ -441,7 +471,7 @@ $("#recordModal").on('submit','#recordForm', function(event){
|
||||
})
|
||||
}
|
||||
else {
|
||||
//code for add
|
||||
//code for edit
|
||||
event.preventDefault();
|
||||
$('#save').attr('disabled','disabled');
|
||||
var formData = $(this).serializeJSON();
|
||||
@ -474,7 +504,40 @@ $("#recordModal").on('submit','#recordForm', function(event){
|
||||
|
||||
});
|
||||
|
||||
//delete
|
||||
//add json modal
|
||||
$("#jsonModal").on('submit','#jsonForm', function(event){
|
||||
event.preventDefault();
|
||||
$('#json_add').attr('disabled','disabled');
|
||||
jsonString = $('#jsontext').val();
|
||||
$.ajax({
|
||||
url:"/stratins/",
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader('X-API-Key',
|
||||
API_KEY); },
|
||||
method:"POST",
|
||||
contentType: "application/json",
|
||||
dataType: "json",
|
||||
data: jsonString,
|
||||
success:function(data){
|
||||
$('#jsonForm')[0].reset();
|
||||
window.$('#jsonModal').modal('hide');
|
||||
$('#json_add').attr('disabled', false);
|
||||
setTimeout(function () {
|
||||
runnerRecords.ajax.reload();
|
||||
stratinRecords.ajax.reload();
|
||||
}, 750)
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
var err = eval("(" + xhr.responseText + ")");
|
||||
window.alert(JSON.stringify(xhr));
|
||||
console.log(JSON.stringify(xhr));
|
||||
$('#json_add').attr('disabled', false);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
//delete modal
|
||||
$("#delModal").on('submit','#delForm', function(event){
|
||||
event.preventDefault();
|
||||
$('#delete').attr('disabled','disabled');
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
const momentumIndicatorNames = ["roc", "slope"]
|
||||
var indList = []
|
||||
var ws = null;
|
||||
function connect(event) {
|
||||
@ -54,7 +55,7 @@ function connect(event) {
|
||||
|
||||
if (parsed_data.hasOwnProperty("indicators")) {
|
||||
var indicators = parsed_data.indicators
|
||||
//if there are indicators it means there must be at least two keys (first time is there everytime)
|
||||
//if there are indicators it means there must be at least two keys (except time which is always present)
|
||||
if (Object.keys(indicators).length > 1) {
|
||||
for (const [key, value] of Object.entries(indicators)) {
|
||||
if (key !== "time") {
|
||||
@ -63,10 +64,19 @@ function connect(event) {
|
||||
if (searchObject == undefined) {
|
||||
console.log("object new - init and add")
|
||||
var obj = {name: key, series: null}
|
||||
if (momentumIndicatorNames.includes(key)) {
|
||||
obj.series = chart.addLineSeries({
|
||||
priceScaleId: 'left',
|
||||
title: key,
|
||||
lineWidth: 1,
|
||||
})
|
||||
}
|
||||
else {
|
||||
obj.series = chart.addLineSeries({
|
||||
title: key,
|
||||
lineWidth: 1,
|
||||
})
|
||||
}
|
||||
obj.series.update({
|
||||
time: indicators.time,
|
||||
value: value});
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
.legend {
|
||||
position: absolute;
|
||||
color: #050505;
|
||||
left: 60px;
|
||||
left: 115px;
|
||||
top: 99px;
|
||||
z-index: 1;
|
||||
font-size: 16px;
|
||||
|
||||
@ -116,7 +116,9 @@ class StrategyOrderLimitVykladaci(Strategy):
|
||||
ic(key)
|
||||
#nejprve vyhodime z pendingbuys
|
||||
self.state.vars.pendingbuys.pop(key, False)
|
||||
self.interface.cancel(key)
|
||||
res = self.interface.cancel(key)
|
||||
if res < 0:
|
||||
print("ERROR CANCEL PENDING BUYS")
|
||||
self.state.vars.pendingbuys={}
|
||||
self.state.vars.jevylozeno = 0
|
||||
print("cancel pending buys end")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -334,7 +334,11 @@ class Strategy:
|
||||
if len(self.state.indicators) > 0:
|
||||
rt_out["indicators"] = dict()
|
||||
for key, value in self.state.indicators.items():
|
||||
rt_out["indicators"][key] = value[-1]
|
||||
#odchyceny pripad, kdy indikatory jsou inicializovane, ale jeste v nich nejsou data, pak do WS nic neposilame
|
||||
try:
|
||||
rt_out["indicators"][key]= value[-1]
|
||||
except IndexError:
|
||||
pass
|
||||
print(rt_out)
|
||||
|
||||
print("RTQUEUE INSERT")
|
||||
@ -344,10 +348,6 @@ class Strategy:
|
||||
print("RTQUEUE", self.rtqueue)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# inicializace poplatna typu strategie (např. u LIMITu dotažení existující limitky)
|
||||
def strat_init(self):
|
||||
pass
|
||||
|
||||
Binary file not shown.
@ -14,6 +14,18 @@ from v2realbot.common.model import StrategyInstance, Runner
|
||||
from typing import List
|
||||
import tomli
|
||||
from v2realbot.config import DATA_DIR
|
||||
import requests
|
||||
|
||||
def send_to_telegram(message):
|
||||
apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE'
|
||||
chatID = '5029424778'
|
||||
apiURL = f'https://api.telegram.org/bot{apiToken}/sendMessage'
|
||||
|
||||
try:
|
||||
response = requests.post(apiURL, json={'chat_id': chatID, 'text': message})
|
||||
print(response.text)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
#datetime to timestamp
|
||||
def json_serial(obj):
|
||||
|
||||
Reference in New Issue
Block a user