docasne ulozeni DYNAMICKY REFACTORING _NEW

This commit is contained in:
David Brazda
2023-07-11 19:25:08 +02:00
parent 2551ccf729
commit 2a9b2a1c7c
17 changed files with 1829 additions and 36 deletions

47
testy/pricecrosses.py Normal file
View File

@ -0,0 +1,47 @@
test1_threshold = 28.905
bacma = []
bacma.append([28.91])
bacma.append([28.91,28.90])
bacma.append([28.91,28.90,28.89])
bacma.append([28.91,28.90,28.89,28.88])
bacma.append([28.91,28.90,28.89,28.88,28.87])
bacma.append([28.91,28.90,28.89,28.88,28.87,28.86])
def crossed_up(threshold, list):
"""check if threshold has crossed up last thresholdue in list"""
try:
if threshold < list[-1] and threshold >= list[-2]:
return True
else:
return False
except IndexError:
return False
def crossed_down(threshold, list):
"""check if threshold has crossed down last thresholdue in list"""
try:
if threshold > list[-1] and threshold <= list[-2]:
return True
else:
return False
except IndexError:
return False
def crossed(threshold, list):
"""check if threshold has crossed last thresholdue in list"""
if crossed_down(threshold, list) or crossed_up(threshold, list):
return True
else:
return False
for i in bacma:
print(i)
print(f"threshold crossed down {i}", threshold_crossed_down(test1_threshold, i))
print(f"threshold crossed up {i}", threshold_crossed_up(test1_threshold, i))

View File

@ -157,14 +157,14 @@ def next(data, state: StrategyState):
pendingbuys_new[str(o.id)]=float(o.limit_price) pendingbuys_new[str(o.id)]=float(o.limit_price)
if pendingbuys_new != state.vars.pendingbuys: if pendingbuys_new != state.vars.pendingbuys:
state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys) state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = str(state.vars.pendingbuys))
print("ROZDILNA PENDINGBUYS přepsána") print("ROZDILNA PENDINGBUYS přepsána")
print("OLD",state.vars.pendingbuys) print("OLD",state.vars.pendingbuys)
state.vars.pendingbuys = unpackb(packb(pendingbuys_new)) state.vars.pendingbuys = unpackb(packb(pendingbuys_new))
print("NEW", state.vars.pendingbuys) print("NEW", state.vars.pendingbuys)
else: else:
print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys) print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys)
state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys) state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = str(state.vars.pendingbuys))
print("OLD jevylozeno", state.vars.jevylozeno) print("OLD jevylozeno", state.vars.jevylozeno)
if len(state.vars.pendingbuys) > 0: if len(state.vars.pendingbuys) > 0:
state.vars.jevylozeno = 1 state.vars.jevylozeno = 1
@ -952,7 +952,7 @@ def next(data, state: StrategyState):
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
#lp = state.interface.get_last_price(symbol=state.symbol) #lp = state.interface.get_last_price(symbol=state.symbol)
lp = data['close'] lp = data['close']
state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars) state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", pb=str(state.vars.pendingbuys), last_price=lp, data=data, stratvars=state.vars)
state.ilog(e="Indikatory", msg=str(get_last_ind_vals())) state.ilog(e="Indikatory", msg=str(get_last_ind_vals()))
eval_buy() eval_buy()

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,16 @@ from alpaca.data.enums import Exchange
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}") # raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
class Intervals(BaseModel):
start: str
end: str
# Define the data model for the TestLists
class TestList(BaseModel):
id: Optional[UUID | str | None] = None
name: str
dates: List[Intervals]
#for GUI to fetch historical trades on given symbol #for GUI to fetch historical trades on given symbol
class Trade(BaseModel): class Trade(BaseModel):
symbol: str symbol: str

View File

@ -1,6 +1,6 @@
from v2realbot.enums.enums import RecordType, StartBarAlign from v2realbot.enums.enums import RecordType, StartBarAlign
from datetime import datetime, timedelta from datetime import datetime, timedelta
from v2realbot.utils.utils import ltp from v2realbot.utils.utils import ltp, send_to_telegram
from alpaca.trading.client import TradingClient from alpaca.trading.client import TradingClient
from alpaca.trading.requests import MarketOrderRequest, TakeProfitRequest, LimitOrderRequest, ReplaceOrderRequest, GetOrdersRequest from alpaca.trading.requests import MarketOrderRequest, TakeProfitRequest, LimitOrderRequest, ReplaceOrderRequest, GetOrdersRequest
from alpaca.trading.enums import OrderSide, TimeInForce, OrderClass, OrderStatus, QueryOrderStatus from alpaca.trading.enums import OrderSide, TimeInForce, OrderClass, OrderStatus, QueryOrderStatus
@ -8,6 +8,7 @@ from alpaca.trading.models import Order, Position
from alpaca.common.exceptions import APIError from alpaca.common.exceptions import APIError
from v2realbot.config import Keys from v2realbot.config import Keys
from v2realbot.interfaces.general_interface import GeneralInterface from v2realbot.interfaces.general_interface import GeneralInterface
from traceback import format_exc
""""" """""
Live interface with Alpaca for LIVE and PAPER trading. Live interface with Alpaca for LIVE and PAPER trading.
""""" """""
@ -159,12 +160,15 @@ class LiveInterface(GeneralInterface):
a : Position = self.trading_client.get_open_position(self.symbol) a : Position = self.trading_client.get_open_position(self.symbol)
self.avgp, self.poz = float(a.avg_entry_price), int(a.qty) self.avgp, self.poz = float(a.avg_entry_price), int(a.qty)
return a.avg_entry_price, a.qty return a.avg_entry_price, a.qty
except APIError as e: except (APIError, Exception) as e:
#no position #no position
if e.code == 40410000: return 0,0 if e.code == 40410000: return 0,0
else: else:
reason = "Exception when calling LIVE interface pos, REPEATING:" + str(e) + format_exc()
print("API ERROR: Nepodarilo se ziskat pozici.", reason)
send_to_telegram(reason)
#raise Exception(e) #raise Exception(e)
return -1 return -1,-1
"""get open orders ->list(Order)""" """get open orders ->list(Order)"""
def get_open_orders(self, symbol: str, side: OrderSide = OrderSide.SELL): # -> list(Order): def get_open_orders(self, symbol: str, side: OrderSide = OrderSide.SELL): # -> list(Order):

View File

@ -38,6 +38,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script>
<!-- <script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script> --> <!-- <script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script> -->
<script src="/static/js/fast-toml.js" type="text/javascript"></script> <script src="/static/js/fast-toml.js" type="text/javascript"></script>
</head> </head>
<body> <body>
<div id="main" class="mainConteiner flex-container content"> <div id="main" class="mainConteiner flex-container content">
@ -503,6 +504,38 @@
</div> </div>
</div> </div>
</div> </div>
<div id="TestListContainer" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#TestListInner" aria-expanded="true">
<h4>TestList Configuration</h4>
</label>
<div id="TestListInner" class="collapse show">
<div>
<form id="recordFormTestList">
<input type="hidden" id="recordId">
<label for="recordName">Name:</label>
<input type="text" id="recordName" required>
<br>
<!-- TODO predelat na intervaly v ramci dne (tzn. 1.1. 9:30 - 1.1. 9:45) -->
<!-- tzn. jeden zaznam v poli = start + end -->
<label for="datepickerstart">Start:</label>
<input type="datetime-local" id="datepickerstart" step="1">
<label for="datepickerend">End:</label>
<input type="datetime-local" id="datepickerend" step="1">
<button type="button" id="addTagBtn" class="btn btn-outline-success btn-sm">Add Date</button>
<br>
<div id="tagContainer"></div>
<br>
<button type="submit" id="saveBtn" class="btn btn-outline-success btn-sm">Save</button>
<button type="button" id="cancelBtn" class="btn btn-outline-success btn-sm">Cancel</button>
</form>
<div id="output"></div>
</div>
<div>
<h4>Test Lists</h4>
<div id="recordsList"></div>
</div>
</div>
</div>
<div id="configContainer" class="flex-items"> <div id="configContainer" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#configInner" aria-expanded="true"> <label data-bs-toggle="collapse" data-bs-target="#configInner" aria-expanded="true">
<h4>Config</h4> <h4>Config</h4>
@ -523,5 +556,6 @@
<script src="/static/js/livewebsocket.js"></script> <script src="/static/js/livewebsocket.js"></script>
<script src="/static/js/realtimechart.js"></script> <script src="/static/js/realtimechart.js"></script>
<script src="/static/js/mytables.js"></script> <script src="/static/js/mytables.js"></script>
<script src="/static/js/testlist.js"></script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,244 @@
//TODO pridat podporu pro intervaly
//pridat skrz proklik intervalu na 1m chart s timto intervalem - pripadne odkaz na tradingview
$(document).ready(function() {
var apiUrl = '/testlists';
var datesArray = [];
//$('#datepicker').datepicker();
function populateForm(record) {
$('#recordId').val(record.id);
$('#recordName').val(record.name);
datesArray = record.dates;
$('#tagContainer').empty();
datesArray.forEach(function(dates) {
var tag = $('<div class="tag">' + dates.start + " --- " + dates.end + '<span class="close">X</span></div>');
tag.find('.close').click(function() {
$(this).parent().remove();
});
$('#tagContainer').append(tag);
});
}
function renderRecords(records) {
var recordsList = $('#recordsList');
recordsList.empty();
records.forEach(function(record) {
var recordItem = $('<div class="recordItem"></div>');
var recordDetails = $('<div class="recordDetails"></div>').html('<strong>ID:</strong> ' + record.id + '<br><strong>Name:</strong> ' + record.name + '<br><strong>Dates:</strong> ');
record.dates.forEach(function(interval) {
var intervalItem = $('<div class="intervalContainer"></div>').html('<strong>Start:</strong> ' + interval.start + '<br><strong>End:</strong> ' + interval.end);
recordDetails.append(intervalItem);
});
var editButton = $('<button class="btn btn-outline-success btn-sm">Edit</button>');
var deleteButton = $('<button class="btn btn-outline-success btn-sm">X</button>');
editButton.click(function() {
editRecord(record);
});
deleteButton.click(function() {
var confirmed = window.confirm("Confirm?");
if (confirmed) {
deleteRecord(record);
}
});
recordItem.append(recordDetails);
recordItem.append(editButton);
recordItem.append(deleteButton);
recordsList.append(recordItem);
});
}
function editRecord(record) {
populateForm(record);
// Hide Edit button, show Save and Cancel buttons
$('.editButton').hide();
$('.deleteButton').hide();
$('#saveBtn').show();
$('#cancelBtn').show();
// Disable input fields
$('#recordName').prop('disabled', false);
$('#addTagBtn').prop('disabled', false);
$('#datepickerstart').prop('disabled', false);
$('#datepickerend').prop('disabled', false);
}
function cancelEdit() {
// Clear form
$('#recordId').val('');
$('#recordName').val('');
$('#datepickerstart').val('');
$('#datepickerend').val('');
$('#tagContainer').empty();
datesArray = [];
// Hide Save and Cancel buttons, show Edit button
$('.editButton').show();
$('.deleteButton').show();
// $('#saveBtn').hide();
// $('#cancelBtn').hide();
// Disable input fields
$('#recordName').prop('disabled', false);
$('#addTagBtn').prop('disabled', false);
$('#datepickerstart').prop('disabled', false);
$('#datepickerend').prop('disabled', false);
}
$('#addTagBtn').click(function() {
var dateTextStart = $('#datepickerstart').val().trim();
var dateTextEnd = $('#datepickerend').val().trim();
if ((dateTextStart !== '') && (dateTextEnd !== '')) {
var tag = $('<div class="tag">' + dateTextStart + " --- " + dateTextEnd + '<span class="close">X</span></div>');
tag.find('.close').click(function() {
$(this).parent().remove();
});
$('#tagContainer').append(tag);
var interval = {}
interval["start"] = dateTextStart
interval["end"] = dateTextEnd
datesArray.push(interval);
$('#datepicker').val('');
}
});
$('#recordFormTestList').submit(function(e) {
e.preventDefault();
var recordId = $('#recordId').val();
var recordName = $('#recordName').val().trim();
if (recordName === '') {
alert('Please enter a name.');
return;
}
var recordDates = datesArray;
var recordData = {
id: recordId,
name: recordName,
dates: recordDates
};
if (recordId) {
// Update existing record
console.log("update")
updateRecord(recordData);
} else {
// Create new record¨
console.log("create")
createRecord(recordData);
}
});
$('#cancelBtn').click(function() {
// Clear form
cancelEdit();
});
$('#tagContainer').on('click', '.tag .close', function() {
var tag = $(this).parent();
var dateText = tag.text();
datesArray = datesArray.filter(function(date) {
tagcontent = date.start + " --- " + date.end
return tagcontent !== dateText;
});
tag.remove();
});
function getRecords() {
$.ajax({
url: apiUrl,
method: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
success: function(data) {
renderRecords(data);
},
error: function(xhr, status, error) {
console.log(error);
}
});
}
function createRecord(recordData) {
jsonString = JSON.stringify(recordData);
$.ajax({
url: apiUrl,
method: 'POST',
contentType: "application/json",
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
data: jsonString,
success: function(data) {
getRecords();
cancelEdit();
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
console.log(JSON.stringify(xhr));
}
});
}
function updateRecord(recordData) {
var recordId = recordData.id;
jsonString = JSON.stringify(recordData);
$.ajax({
url: apiUrl + '/' + recordId,
method: 'PUT',
contentType: "application/json",
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
data: jsonString,
success: function(data) {
getRecords();
cancelEdit();
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
console.log(JSON.stringify(xhr));
}
});
}
function deleteRecord(recordData) {
$.ajax({
url: apiUrl + '/' + recordData.id,
method: 'DELETE',
contentType: "application/json",
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
success: function(data) {
getRecords();
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
console.log(JSON.stringify(xhr));
}
});
}
// Load initial records
getRecords();
});

View File

@ -28,8 +28,10 @@ indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, pri
{name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false}, {name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
{name: "slopeNEW", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false}, {name: "slopeNEW", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
{name: "slope10", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slope10", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slope20", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slope10puv", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slope10puv", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slope30", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slopeS", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slopeLP", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false}, {name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
{name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},

View File

@ -396,4 +396,81 @@ pre {
'wght' 300, 'wght' 300,
'GRAD' 0, 'GRAD' 0,
'opsz' 24 'opsz' 24
} }
/* TestList part generated by ChatGPT */
.recordItem {
border: 1px solid #797979;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
}
.recordDetails {
margin-bottom: 10px;
}
/* .editButton,
#saveBtn,
#cancelBtn,
#addTagBtn {
background-color: #4CAF50;
color: white;
border: none;
padding: 5px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin-top: 5px;
cursor: pointer;
}
.editButton:hover,
#saveBtn:hover,
#cancelBtn:hover,
#addTagBtn:hover {
background-color: #45a049;
}
.editButton:active,
#saveBtn:active,
#cancelBtn:active,
#addTagBtn:active {
background-color: #3e8e41;
} */
.recordItem:after {
content: "";
display: table;
clear: both;
}
.recordItem .close {
visibility: hidden;
font-weight: bold;
margin-left: 5px;
}
.recordItem:hover .close {
visibility: visible;
}
.close {
color: #888;
}
.tag {
display: inline-block;
background-color: #f2f2f2;
padding: 5px 10px;
border-radius: 10px;
margin-right: 5px;
}
#recordName:disabled,
#addTagBtn:disabled,
#datepicker:disabled {
background-color: #f2f2f2;
}

View File

@ -77,11 +77,16 @@ class StrategyOrderLimitVykladaciNormalizedMYSELL(Strategy):
#ic("notifikace sell mazeme limitku a update pozic") #ic("notifikace sell mazeme limitku a update pozic")
#updatujeme pozice #updatujeme pozice
self.state.avgp, self.state.positions = self.interface.pos() a,p = self.interface.pos()
#pri chybe api nechavame puvodni hodnoty
if a != -1:
self.state.avgp, self.state.positions = a,p
#ic(self.state.avgp, self.state.positions) #ic(self.state.avgp, self.state.positions)
self.state.vars.limitka = None self.state.vars.limitka = None
self.state.vars.limitka_price = None self.state.vars.limitka_price = None
self.state.vars.lastbuyindex = -5 #resetujeme lastbuyindex, pokud neni v konfiguraci jinak
if safe_get(self.state.vars, "last_buy_offset_reset_after_sell", True):
self.state.vars.lastbuyindex = -5
self.state.vars.jevylozeno = 0 self.state.vars.jevylozeno = 0
await self.state.cancel_pending_buys() await self.state.cancel_pending_buys()
self.state.ilog(e="Příchozí SELL - FILL nebo CANCEL - mazeme limitku a pb", msg=data.order.status, orderid=str(data.order.id), pb=self.state.vars.pendingbuys) self.state.ilog(e="Příchozí SELL - FILL nebo CANCEL - mazeme limitku a pb", msg=data.order.status, orderid=str(data.order.id), pb=self.state.vars.pendingbuys)
@ -125,11 +130,13 @@ class StrategyOrderLimitVykladaciNormalizedMYSELL(Strategy):
if order != -1: if order != -1:
print("ukladame pendingbuys") print("ukladame pendingbuys")
self.state.vars.pendingbuys[str(order)]=price self.state.vars.pendingbuys[str(order)]=price
ulozena_cena = self.state.vars.pendingbuys[str(order)]
self.state.ilog(e=f"Odeslan buy_l a ulozeno do pb {ulozena_cena=}", order=str(order), pb=str(self.state.vars.pendingbuys))
self.state.blockbuy = 1 self.state.blockbuy = 1
self.state.vars.lastbuyindex = self.state.bars['index'][-1] self.state.vars.lastbuyindex = self.state.bars['index'][-1]
#ic(self.state.blockbuy) #ic(self.state.blockbuy)
#ic(self.state.vars.lastbuyindex) #ic(self.state.vars.lastbuyindex)
self.state.ilog(e="Odeslan buy_l a ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys) #self.state.ilog(e="Odeslan buy_l a ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys)
else: else:
self.state.ilog(e="Chyba - nepodarilo se odeslat buy_l - nebylo ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys) self.state.ilog(e="Chyba - nepodarilo se odeslat buy_l - nebylo ulozeno do pb", order=str(order), pb=self.state.vars.pendingbuys)

View File

@ -246,9 +246,13 @@ class Strategy:
""""refresh positions and avgp - for CBAR once per confirmed, for BARS each time""" """"refresh positions and avgp - for CBAR once per confirmed, for BARS each time"""
def refresh_positions(self, item): def refresh_positions(self, item):
if self.rectype == RecordType.BAR: if self.rectype == RecordType.BAR:
self.state.avgp, self.state.positions = self.interface.pos() a,p = self.interface.pos()
if a != -1:
self.state.avgp, self.state.positions = a,p
elif self.rectype == RecordType.CBAR and item['confirmed'] == 1: elif self.rectype == RecordType.CBAR and item['confirmed'] == 1:
self.state.avgp, self.state.positions= self.interface.pos() a,p = self.interface.pos()
if a != -1:
self.state.avgp, self.state.positions = a,p
"""update state.last_trade_time a time of iteration""" """update state.last_trade_time a time of iteration"""
def update_times(self, item): def update_times(self, item):

View File

@ -9,7 +9,7 @@ import decimal
from v2realbot.enums.enums import RecordType, Mode, StartBarAlign from v2realbot.enums.enums import RecordType, Mode, StartBarAlign
import pickle import pickle
import os import os
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals
from typing import List from typing import List
import tomli import tomli
from v2realbot.config import DATA_DIR, QUIET_MODE,NORMALIZED_TICK_BASE_PRICE from v2realbot.config import DATA_DIR, QUIET_MODE,NORMALIZED_TICK_BASE_PRICE
@ -23,6 +23,33 @@ import numpy as np
import pandas as pd import pandas as pd
from collections import deque from collections import deque
def crossed_up(threshold, list):
"""check if threshold has crossed up last thresholdue in list"""
try:
if threshold < list[-1] and threshold >= list[-2]:
return True
else:
return False
except IndexError:
return False
def crossed_down(threshold, list):
"""check if threshold has crossed down last thresholdue in list"""
try:
if threshold > list[-1] and threshold <= list[-2]:
return True
else:
return False
except IndexError:
return False
def crossed(threshold, list):
"""check if threshold has crossed last thresholdue in list"""
if crossed_down(threshold, list) or crossed_up(threshold, list):
return True
else:
return False
def get_tick(price: float, normalized_ticks: float = 0.01): def get_tick(price: float, normalized_ticks: float = 0.01):
""" """
prevede normalizovany tick na tick odpovidajici vstupni cene prevede normalizovany tick na tick odpovidajici vstupni cene
@ -50,34 +77,47 @@ def eval_cond_dict(cond: dict) -> tuple[bool, str]:
buy_cond["5siddngle"] = False buy_cond["5siddngle"] = False
group eval rules. 1. single 2. AND 3. ORS group eval rules. 1. single 2. AND 3. ORS
""" """
msg = "" msg = {}
ret = False ret = []
#eval single cond
for klic in cond:
if klic in ["AND","OR"]: continue
else:
if cond[klic]:
return True, klic
##check AND group ##check AND group
if 'AND' in cond.keys(): if 'AND' in cond.keys() and len(cond["AND"])>0:
msg["AND"] = {}
for key in cond["AND"]: for key in cond["AND"]:
res = cond["AND"][key]
ret.append(res)
msg["AND"][key] = (str(res).upper() if res else str(res))
#msg += "[AND]" + key + ":" + (str(res).upper() if res else str(res)) + " "
if cond["AND"][key]: if all(ret):
ret = True
msg += key + " AND "
else:
ret = False
break
if ret:
return True, msg return True, msg
#eval OR groups #eval OR groups
if "OR" in cond.keys(): if "OR" in cond.keys() and len(cond["OR"])>0:
ret = []
msg["OR"] = {}
for key in cond["OR"]: for key in cond["OR"]:
if cond["OR"][key]: res = cond["OR"][key]
return True, key ret.append(res)
msg["OR"][key] = (str(res).upper() if res else str(res))
return False, None #msg += "[OR]" + key + ":" + (str(res).upper() if res else str(res)) + " "
if any(ret):
return True, msg
#pokud nemame zadne AND ani OR, tak to je single cond
ret = []
for key in cond:
if key == "AND" or key == "OR":
continue
#je to vlastne to same jako OR
res = cond[key]
ret.append(res)
msg[key] = (str(res).upper() if res else str(res))
#msg += key + ":" + (str(res).upper() if res else str(res)) + " "
#pokud predchozi single obsahoval True, vratime True jinak False
return any(ret), msg
def Average(lst): def Average(lst):
return sum(lst) / len(lst) return sum(lst) / len(lst)
@ -132,6 +172,8 @@ def json_serial(obj):
return obj.__dict__ return obj.__dict__
if type(obj) is RunArchiveDetail: if type(obj) is RunArchiveDetail:
return obj.__dict__ return obj.__dict__
if type(obj) is Intervals:
return obj.__dict__
raise TypeError (str(obj)+"Type %s not serializable" % type(obj)) raise TypeError (str(obj)+"Type %s not serializable" % type(obj))