From 3a1b1550fdcfca02ac55fa71efd9a08c03118f49 Mon Sep 17 00:00:00 2001 From: David Brazda Date: Mon, 1 May 2023 19:11:17 +0200 Subject: [PATCH] refaktor gui jdeme na live --- testy/tinyDBselect.py | 32 ++++++++ v2realbot/__pycache__/config.cpython-310.pyc | Bin 2779 -> 2779 bytes .../common/__pycache__/model.cpython-310.pyc | Bin 5996 -> 6187 bytes v2realbot/common/model.py | 5 ++ v2realbot/config.py | 2 +- v2realbot/controller/services.py | 24 ++++-- v2realbot/main.py | 12 ++- v2realbot/static/index.html | 48 ++++++++++-- v2realbot/static/js/archivechart.js | 74 +++++++++++------- v2realbot/static/js/archivetables.js | 61 +++++++++++++-- v2realbot/static/js/livewebsocket.js | 2 +- v2realbot/static/js/realtimechart.js | 40 +++++----- v2realbot/static/main.css | 2 +- 13 files changed, 229 insertions(+), 73 deletions(-) create mode 100644 testy/tinyDBselect.py diff --git a/testy/tinyDBselect.py b/testy/tinyDBselect.py new file mode 100644 index 0000000..5a7aae1 --- /dev/null +++ b/testy/tinyDBselect.py @@ -0,0 +1,32 @@ + +from typing import Any, List +from uuid import UUID, uuid4 +import pickle +from alpaca.data.historical import StockHistoricalDataClient +from alpaca.data.requests import StockTradesRequest, StockBarsRequest +from alpaca.data.enums import DataFeed +from alpaca.data.timeframe import TimeFrame +from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account +from v2realbot.common.model import StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveDetail, RunArchiveChange +from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string, json_serial +from datetime import datetime +from threading import Thread, current_thread, Event, enumerate +from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR +import importlib +from queue import Queue +from tinydb import TinyDB, Query, where +from tinydb.operations import set +import json +from rich import print + +arch_header_file = DATA_DIR + "/arch_header.json" +arch_detail_file = DATA_DIR + "/arch_detail.json" +#db layer to store runner archive +db_arch_h = TinyDB(arch_header_file, default=json_serial) +db_arch_d = TinyDB(arch_detail_file, default=json_serial) + + +# res = db_arch_h.update(set('note', "ahoj"), where('id') == "74aa524e-3ed4-41fb-8166-f20946520344") +# print(res) +res = db_arch_d.all() +print(res) \ No newline at end of file diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index 63e3332e72ae1e84d88591022babc78dc6c17ec6..e3b2ecba7b7a31c9417dea6143037e9683b80e33 100644 GIT binary patch delta 183 zcmW-bJsQD400nnhB9SE$NhJQcgcDFws9vLaiSN@mfWdNS!|poJX@>;Z90XZbFQFctV!3HYs{z4s%&K{S8UTO z6ase8rH_ySB6bloM2``YOdeA78Dqd6hNh0FF#gvG6HJ+6RyTRhsQhf2%Xh_$y?=Z6 Nt$fww_P(%g)h~-EE8747 delta 182 zcmW-bI}*WA07YNq5y8t>{QnADumT!m%uwAzbrUlhOHjxLvIUlq<)qbQ2TG6Aol~76 zDk61Lsv$J1-Ja)6C3g$XMX>%f;Kmm1hXKzPTfqjKsbKR_fv>GarA=uI=)@-7SSFGl z{Zt}kfHp%!Y@@>nU3So;L_apJ0}R>4h&_yTozTMcUuW!N&H)xRotKo^=g>Np6+Kq| O_BQ#^cvtha^)kP|nJUx( diff --git a/v2realbot/common/__pycache__/model.cpython-310.pyc b/v2realbot/common/__pycache__/model.cpython-310.pyc index 3759e126cf012eeaf7397d9b865b2055aaae7b9c..9978461870e3b98eb65eb37b9421296dc66f7eab 100644 GIT binary patch delta 304 zcmaE(x7vU=pO=@50SMxb_@{JCjxrII2a%%G{T zIe~GaAfw#m`K+?4Da=3-mRkZrrFo7;$r+htsm>XRdFiP|(m>OS41k26CfnqFTvCjR zlOJ+Oh^7NY<^pjs8<5~);9%roEJ~l;$SS+}qtG%&=WL*8kr0Rw1`%c;!W=~80Et^H zDVfP7MY$lpGKdHU5h@@e4@BgHhysu`tQkP&qRHPybQv>1hEH}9UBy^9`K_puauHBw z2M`zY0SS-;z>tZ9QGl@sB 0: #print(db.runners) for i in db.runners: - i.run_profit = round(i.run_instance.state.profit,2) + i.run_profit = round(float(i.run_instance.state.profit),2) i.run_trade_count = len(i.run_instance.state.tradeList) i.run_positions = i.run_instance.state.positions - i.run_avgp = round(i.run_instance.state.avgp,3) + i.run_avgp = round(float(i.run_instance.state.avgp),3) return (0, db.runners) else: return (0, []) @@ -419,10 +419,10 @@ def archive_runner(runner: Runner, strat: StrategyInstance): bt_from=bp_from, bt_to = bp_to, stratvars = strat.state.vars, - profit=round(strat.state.profit,2), + profit=round(float(strat.state.profit),2), trade_count=len(strat.state.tradeList), end_positions=strat.state.positions, - end_positions_avgp=round(strat.state.avgp,3), + end_positions_avgp=round(float(strat.state.avgp),3), open_orders=9999 ) @@ -437,7 +437,7 @@ def archive_runner(runner: Runner, strat: StrategyInstance): print("archive runner finished") return 0, str(resh) + " " + str(resd) except Exception as e: - print(str(e)) + print("Exception in archive_runner: " + str(e)) return -2, str(e) def get_all_archived_runners(): @@ -454,13 +454,23 @@ def delete_archived_runners_byID(id: UUID): return 0, str(resh) + " " + str(resd) except Exception as e: return -2, str(e) + +#edit archived runner note +def edit_archived_runners(runner_id: UUID, archChange: RunArchiveChange): + try: + res = db_arch_h.update(set('note', archChange.note), where('id') == str(runner_id)) + if len(res) == 0: + return -1, "not found "+str(runner_id) + return 0, runner_id + except Exception as e: + return -2, str(e) def get_all_archived_runners_detail(): res = db_arch_d.all() return 0, res def get_archived_runner_details_byID(id: UUID): - res = db_arch_d.get(where('id') == id) + res = db_arch_d.get(where('id') == str(id)) if res==None: return -2, "not found" else: diff --git a/v2realbot/main.py b/v2realbot/main.py index 12391e7..33e2221 100644 --- a/v2realbot/main.py +++ b/v2realbot/main.py @@ -13,7 +13,7 @@ from fastapi.security import APIKeyHeader import uvicorn from uuid import UUID import v2realbot.controller.services as cs -from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveDetail, Bar +from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveDetail, Bar, RunArchiveChange from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query from fastapi.responses import HTMLResponse, FileResponse from fastapi.staticfiles import StaticFiles @@ -282,6 +282,16 @@ def _delete_archived_runners_byID(runner_id): elif res < 0: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Error: {res}:{id}") +#edit archived runner ("note",..) +@app.patch("/archived_runners/{runner_id}", dependencies=[Depends(api_key_auth)]) +def _edit_archived_runners(archChange: RunArchiveChange, runner_id: UUID): + res, id = cs.edit_archived_runners(runner_id=runner_id, archChange=archChange) + if res == 0: return runner_id + elif res == -1: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Error not found: {res}:{runner_id}") + else: + raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not changed: {res}:{runner_id}") + #get all archived runners detail @app.get("/archived_runners_detail/", dependencies=[Depends(api_key_auth)]) def _get_all_archived_runners_detail() -> list[RunArchiveDetail]: diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 0fbd44d..7fbdd62 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -149,8 +149,9 @@
- + +
@@ -194,13 +195,44 @@ + +
@@ -319,7 +351,7 @@ @@ -341,7 +373,7 @@ @@ -375,11 +407,11 @@
- +
- +
@@ -394,7 +426,7 @@ - +
diff --git a/v2realbot/static/js/archivechart.js b/v2realbot/static/js/archivechart.js index 17150a5..95c8152 100644 --- a/v2realbot/static/js/archivechart.js +++ b/v2realbot/static/js/archivechart.js @@ -1,5 +1,6 @@ var tradeDetails = new Map(); var toolTip = null +var CHART_SHOW_TEXT = false //TRANSFORM object returned from RESTA PI get_arch_run_detail //to series and markers required by lightweigth chart //input array object bars = { high: [1,2,3], time: [1,2,3], close: [2,2,2]...} @@ -46,19 +47,23 @@ function transform_data(data) { a_markers = {} timestamp = Date.parse(trade.order.filled_at)/1000 if (trade.order.side == "buy") { - //line pro avgp markers - obj["time"] = timestamp; - obj["value"] = trade.pos_avg_price; - avgp_buy_line.push(obj) + //avgp lajnu vytvarime jen pokud je v tradeventu prumerna cena + if (trade.pos_avg_price !== null) { + //line pro avgp markers + obj["time"] = timestamp; + obj["value"] = trade.pos_avg_price; + avgp_buy_line.push(obj) - //avgp markers pro prumernou cenu aktualnich pozic - a_markers["time"] = timestamp - a_markers["position"] = "aboveBar" - a_markers["color"] = "#e8c76d" - a_markers["shape"] = "arrowDown" -// a_markers["text"] = trade.position_qty + " " + parseFloat(trade.pos_avg_price).toFixed(3) - a_markers["text"] = trade.position_qty - avgp_markers.push(a_markers) + //avgp markers pro prumernou cenu aktualnich pozic + a_markers["time"] = timestamp + a_markers["position"] = "aboveBar" + a_markers["color"] = "#e8c76d" + a_markers["shape"] = "arrowDown" + if (CHART_SHOW_TEXT) + // a_markers["text"] = trade.position_qty + " " + parseFloat(trade.pos_avg_price).toFixed(3) + a_markers["text"] = CHART_SHOW_TEXT ? trade.position_qty + "/" + parseFloat(trade.pos_avg_price).toFixed(3) :trade.position_qty + avgp_markers.push(a_markers) + } } //buy sell markery @@ -66,11 +71,11 @@ function transform_data(data) { marker["time"] = timestamp; // marker["position"] = (trade.order.side == "buy") ? "belowBar" : "aboveBar" marker["position"] = (trade.order.side == "buy") ? "inBar" : "aboveBar" - marker["color"] = (trade.order.side == "buy") ? "blue" : "red" + marker["color"] = (trade.order.side == "buy") ? "#cfcbc2" : "red" //marker["shape"] = (trade.order.side == "buy") ? "arrowUp" : "arrowDown" marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown" - //marker["text"] = trade.qty + " " + trade.price - marker["text"] = trade.qty + //marker["text"] = trade.qty + "/" + trade.price + marker["text"] = CHART_SHOW_TEXT ? trade.qty + "/" + trade.price : trade.qty markers.push(marker) //prevedeme iso data na timestampy @@ -107,8 +112,16 @@ function transform_data(data) { function prepare_data(archRunner, timeframe_amount, timeframe_unit, archivedRunnerDetail) { req = {} req["symbol"] = archRunner.symbol - req["datetime_object_from"] = archRunner.bt_from - req["datetime_object_to"] = archRunner.bt_to + + if (archRunner.mode == "backtest") { + req["datetime_object_from"] = archRunner.bt_from + req["datetime_object_to"] = archRunner.bt_to + } + else + { + req["datetime_object_from"] = archRunner.started + req["datetime_object_to"] = archRunner.stopped + } req["timeframe_amount"] = timeframe_amount req["timeframe_unit"] = timeframe_unit $.ajax({ @@ -120,13 +133,13 @@ function prepare_data(archRunner, timeframe_amount, timeframe_unit, archivedRunn contentType: "application/json", data: req, success:function(data){ - //console.log("bars", JSON.stringify(data)) + console.log("one minute bars", JSON.stringify(data)) data.map((el)=>{ cas = new Date(el.timestamp) el.time = cas.getTime()/1000; delete el.timestamp }); - //console.log("bars_after_transformation", JSON.stringify(data)) + console.log("one min bars_after_transformation", JSON.stringify(data)) oneMinuteBars = data chart_archived_run(archRunner, archivedRunnerDetail, oneMinuteBars); //call function to continue @@ -151,6 +164,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { toolTip.style.display = 'none'; } } + var transformed_data = transform_data(data) //initialize resolutions @@ -262,16 +276,20 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { }, }); + console.log("avgp_buy_line",transformed_data["avgp_buy_line"]) + console.log("avgp_markers",transformed_data["avgp_markers"]) - var avgBuyLine = chart.addLineSeries({ - // title: "avgpbuyline", - color: '#e8c76d', - // color: 'transparent', - lineWidth: 1, - lastValueVisible: false - }); - avgBuyLine.setData(transformed_data["avgp_buy_line"]); - avgBuyLine.setMarkers(transformed_data["avgp_markers"]) + if (transformed_data["avgp_buy_line"].length > 0) { + var avgBuyLine = chart.addLineSeries({ + // title: "avgpbuyline", + color: '#e8c76d', + // color: 'transparent', + lineWidth: 1, + lastValueVisible: false + }); + avgBuyLine.setData(transformed_data["avgp_buy_line"]); + avgBuyLine.setMarkers(transformed_data["avgp_markers"]) + } var markersLine = chart.addLineSeries({ // title: "avgpbuyline", diff --git a/v2realbot/static/js/archivetables.js b/v2realbot/static/js/archivetables.js index 0ca7900..308d8f5 100644 --- a/v2realbot/static/js/archivetables.js +++ b/v2realbot/static/js/archivetables.js @@ -5,6 +5,7 @@ $(document).ready(function () { //disable buttons (enable on row selection) $('#button_show_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled'); + $('#button_edit_arch').attr('disabled','disabled'); //selectable rows in archive table @@ -13,11 +14,13 @@ $(document).ready(function () { $(this).removeClass('selected'); $('#button_show_arch').attr('disabled','disabled'); $('#button_delete_arch').attr('disabled','disabled'); + $('#button_edit_arch').attr('disabled','disabled'); } else { stratinRecords.$('tr.selected').removeClass('selected'); $(this).addClass('selected'); $('#button_show_arch').attr('disabled',false); $('#button_delete_arch').attr('disabled',false); + $('#button_edit_arch').attr('disabled',false); } }); @@ -28,6 +31,13 @@ $(document).ready(function () { $('#delidarchive').val(row.id); }); + //edit button + $('#button_edit_arch').click(function () { + row = archiveRecords.row('.selected').data(); + window.$('#editModalArchive').modal('show'); + $('#editidarchive').val(row.id); + $('#editstratvars').val(JSON.stringify(row.stratvars,null,2)); + }); //show button $('#button_show_arch').click(function () { @@ -44,6 +54,8 @@ $(document).ready(function () { success:function(data){ $('#button_show_arch').attr('disabled',false); $('#chartContainerInner').addClass("show"); + $("#lines").html("
"+JSON.stringify(row.stratvars,null,2)+"
") + //$('#chartArchive').append(JSON.stringify(data,null,2)); console.log(JSON.stringify(data,null,2)); //if lower res is required call prepare_data otherwise call chart_archived_run() @@ -60,6 +72,43 @@ $(document).ready(function () { }); }) +//edit modal +$("#editModalArchive").on('submit','#editFormArchive', function(event){ + event.preventDefault(); + $('#editarchive').attr('disabled','disabled'); + trow = archiveRecords.row('.selected').data(); + note = $('#editnote').val() + var formData = $(this).serializeJSON(); + row = {} + row["id"] = trow.id + row["note"] = note + jsonString = JSON.stringify(row); + console.log("pred odeslanim json string", jsonString) + $.ajax({ + url:"/archived_runners/"+trow.id, + beforeSend: function (xhr) { + xhr.setRequestHeader('X-API-Key', + API_KEY); }, + method:"PATCH", + contentType: "application/json", + // dataType: "json", + data: jsonString, + success:function(data){ + $('#editFormArchive')[0].reset(); + window.$('#editModalArchive').modal('hide'); + $('#editarchive').attr('disabled', false); + archiveRecords.ajax.reload(); + }, + error: function(xhr, status, error) { + var err = eval("(" + xhr.responseText + ")"); + window.alert(JSON.stringify(xhr)); + console.log(JSON.stringify(xhr)); + $('#editarchive').attr('disabled', false); + } + }) +}); + + //delete modal $("#delModalArchive").on('submit','#delFormArchive', function(event){ event.preventDefault(); @@ -121,12 +170,12 @@ var archiveRecords = {data: 'end_positions_avgp', visible: true}, {data: 'open_orders', visible: true} ], - columnDefs: [{ - targets: [4,5,8,9], - render: function ( data, type, row ) { - return format_date(data) - }, - }], + // columnDefs: [{ + // targets: [4,5,8,9], + // render: function ( data, type, row ) { + // return format_date(data) + // }, + // }], order: [[5, 'desc']], paging: true, lengthChange: false, diff --git a/v2realbot/static/js/livewebsocket.js b/v2realbot/static/js/livewebsocket.js index 37d0999..d51f793 100644 --- a/v2realbot/static/js/livewebsocket.js +++ b/v2realbot/static/js/livewebsocket.js @@ -115,7 +115,7 @@ function connect(event) { logcnt++; - row = '
'+logLine.time + " " + logLine.event + ' - '+ (logLine.message == undefined ? "" : logLine.message) +'
' + row = '
'+logLine.time + " " + logLine.event + ' - '+ (logLine.message == undefined ? "" : logLine.message) +'
' str_row = JSON.stringify(logLine.details, null, 2) //row_detail = '
' + str_row + '
' diff --git a/v2realbot/static/js/realtimechart.js b/v2realbot/static/js/realtimechart.js index a23437f..1b342e5 100644 --- a/v2realbot/static/js/realtimechart.js +++ b/v2realbot/static/js/realtimechart.js @@ -8,26 +8,26 @@ function populate_real_time_chart() { $('#chartContainerInner').addClass("show"); //const chartOptions = { layout: { textColor: 'black', background: { type: 'solid', color: 'white' } } }; - //var chartOptions = { width: 1045, height: 600, leftPriceScale: {visible: true}} - var chartOptions = { width: 1045, - height: 600, - leftPriceScale: {visible: true}, - layout: { - background: { - type: 'solid', - color: '#000000', - }, - textColor: '#d1d4dc', - }, - grid: { - vertLines: { - visible: false, - }, - horzLines: { - color: 'rgba(42, 46, 57, 0.5)', - }, - }, - } + var chartOptions = { width: 1045, height: 600, leftPriceScale: {visible: true}} + // var chartOptions = { width: 1045, + // height: 600, + // leftPriceScale: {visible: true}, + // layout: { + // background: { + // type: 'solid', + // color: '#000000', + // }, + // textColor: '#d1d4dc', + // }, + // grid: { + // vertLines: { + // visible: false, + // }, + // horzLines: { + // color: 'rgba(42, 46, 57, 0.5)', + // }, + // }, + // } chart = LightweightCharts.createChart(document.getElementById('chart'), chartOptions); diff --git a/v2realbot/static/main.css b/v2realbot/static/main.css index ed74c29..a0f7644 100644 --- a/v2realbot/static/main.css +++ b/v2realbot/static/main.css @@ -127,7 +127,7 @@ pre { font-size: normal; /* font-weight: bold; */ display: -webkit-inline-box; - background-color: #128faf; + background-color: #dfe4e6; /* color: white; */ padding: 1px; padding-left: 5px;