Fixed issue with fetching historical data and added missing imports.
This commit is contained in:
parent
49c908357f
commit
0bb9780ff6
159
markdown/App.md
159
markdown/App.md
|
|
@ -1,159 +0,0 @@
|
|||
## App Flow Charts
|
||||
|
||||
### App
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
:Create BrighterTrades object;
|
||||
:configuration app;
|
||||
:run app;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /index
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
:Log in user;
|
||||
:Load dynamic data;
|
||||
:Render Landing Page;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /ws
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
repeat
|
||||
:Listen for message;
|
||||
if (Contains json?) then (yse)
|
||||
:Process_received_json();
|
||||
else (no)
|
||||
:Display_message();
|
||||
endif
|
||||
repeatwhile()
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /settings
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
if (Logged in?) then (no)
|
||||
:redirect -> "/index";
|
||||
stop
|
||||
else (yes)
|
||||
:get_setting();
|
||||
:process_command();
|
||||
:redirect -> "/index";
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /history
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
if (Logged in?) then (no)
|
||||
:Return empty data;
|
||||
stop
|
||||
else (yes)
|
||||
:Get current chart view details.;
|
||||
:Request price history for the chart view.;
|
||||
:Return data;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /signup
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
:Return rendered signup page.;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /signout
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
:Logout user.;
|
||||
:Delete client session var.;
|
||||
:redirect -> /index;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /login
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
:Get credentials;
|
||||
:Log in user.;
|
||||
if (success) then (yes)
|
||||
:Set the client session var;
|
||||
else (no)
|
||||
endif
|
||||
:Redirect -> /index;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
### /signup_submit
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
start
|
||||
|
||||
:Receive form data;
|
||||
:Extract email, username, and password;
|
||||
:Validate email format;
|
||||
if (Valid email format?) then (yes)
|
||||
:Validate username and password;
|
||||
if (Valid username and password?) then (yes)
|
||||
:Create new user;
|
||||
if (Success) then (yes)
|
||||
:Set session user;
|
||||
:Redirect to homepage;
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
|
||||
stop
|
||||
|
||||
@enduml
|
||||
```
|
||||
### /indictor_init
|
||||
```plantuml
|
||||
@startuml
|
||||
start
|
||||
|
||||
if (Check if username is provided) then (yes)
|
||||
:Retrieve username from request data;
|
||||
else (no)
|
||||
:Return error response;
|
||||
stop
|
||||
endif
|
||||
|
||||
if (Check if user is logged in) then (yes)
|
||||
:Retrieve chart view for the user;
|
||||
else (no)
|
||||
:Return error response;
|
||||
stop
|
||||
endif
|
||||
|
||||
:Retrieve indicator data for the user;
|
||||
:Return data response;
|
||||
stop
|
||||
|
||||
@endum
|
||||
```
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
## App Flow Charts
|
||||
|
||||
### App
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>app.py</b>
|
||||
————————————————————————————————
|
||||
Initializes the BrighterTrades object, configures the Flask
|
||||
server, defines the endpoints then launches the app.
|
||||
end legend
|
||||
start
|
||||
:Create BrighterTrades object;
|
||||
:Configure app;
|
||||
:Define endpoints;
|
||||
:Run app;
|
||||
stop
|
||||
|
||||
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /index
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/index</b>
|
||||
————————————————————————————————
|
||||
Handles the main landing page, logs in the user,
|
||||
loads dynamic data, and renders the landing page.
|
||||
end legend
|
||||
start
|
||||
:Log in user;
|
||||
:Load dynamic data;
|
||||
:Render Landing Page;
|
||||
stop
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
|
||||
### /ws
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/ws</b>
|
||||
————————————————————————————————
|
||||
Handles WebSocket connections, listens for messages,
|
||||
processes JSON data, and displays messages.
|
||||
end legend
|
||||
start
|
||||
repeat
|
||||
:Listen for message;
|
||||
if (Contains JSON?) then (yes)
|
||||
:Process received JSON;
|
||||
else (no)
|
||||
:Display message;
|
||||
endif
|
||||
repeat while ()
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /settings
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/settings</b>
|
||||
————————————————————————————————
|
||||
Handles settings changes. If user is logged in,
|
||||
processes commands and redirects to index.
|
||||
end legend
|
||||
start
|
||||
if (Logged in?) then (no)
|
||||
:redirect -> "/index";
|
||||
stop
|
||||
else (yes)
|
||||
:get_setting();
|
||||
:process_command();
|
||||
:redirect -> "/index";
|
||||
endif
|
||||
stop
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /history
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————
|
||||
=<b>/history​</b>
|
||||
————————————————————————
|
||||
Fetches candle history for
|
||||
a specific trading pair
|
||||
and timeframe. Returns empty
|
||||
data if user is not logged in.
|
||||
end legend
|
||||
start
|
||||
if (Logged in?) then (no)
|
||||
:Return empty data;
|
||||
stop
|
||||
else (yes)
|
||||
:Get current chart view details;
|
||||
:Request price history for the chart view;
|
||||
:Return data;
|
||||
endif
|
||||
stop
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /signup
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/signup</b>
|
||||
————————————————————————————————
|
||||
Returns the rendered signup page.​
|
||||
end legend
|
||||
start
|
||||
:Return rendered signup page​;
|
||||
stop
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /signout
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/signout</b>
|
||||
————————————————————————————————
|
||||
Logs out the user, deletes the client
|
||||
session variable, and redirects to index.
|
||||
end legend
|
||||
start
|
||||
:Logout user;
|
||||
:Delete client session var;
|
||||
:redirect -> "/index";
|
||||
stop
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
|
||||
### /login
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/login</b>
|
||||
————————————————————————————————
|
||||
Handles user login by receiving credentials,
|
||||
logging in the user, and redirecting to index.
|
||||
end legend
|
||||
start
|
||||
:Get credentials;
|
||||
:Log in user;
|
||||
if (success) then (yes)
|
||||
:Set the client session var;
|
||||
else (no)
|
||||
endif
|
||||
:Redirect -> /index;
|
||||
stop
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
|
||||
### /signup_submit
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/signup_submit</b>
|
||||
————————————————————————————————
|
||||
Handles user signup by receiving form data,​
|
||||
validating email, creating new user,
|
||||
and redirecting to homepage.
|
||||
end legend
|
||||
start
|
||||
:Receive form data;
|
||||
:Extract email, username, and password​;
|
||||
:Validate email format;
|
||||
if (Valid email format?) then (yes)
|
||||
:Validate username and password;
|
||||
if (Valid username and password?) then (yes)
|
||||
:Create new user;
|
||||
if (Success) then (yes)
|
||||
:Set session user;
|
||||
:Redirect to homepage;
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
else (no)
|
||||
:Flash error message;
|
||||
endif
|
||||
stop
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
### /indictor_init
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam legendBackgroundColor lightgreen
|
||||
skinparam defaultFontColor blue
|
||||
skinparam legendAlignment left
|
||||
skinparam defaultFontName "Arial Black"
|
||||
skinparam legendFontSize 12
|
||||
|
||||
skinparam activity {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
legend top
|
||||
————————————————————————————————
|
||||
=<b>/indicator_init</b>
|
||||
————————————————————————————————
|
||||
Initializes the indicators for a given symbol
|
||||
and timeframe, retrieves user and chart view​
|
||||
details, and returns data response.​
|
||||
end legend
|
||||
start
|
||||
if (Check if username is provided) then (yes)
|
||||
:Retrieve username from request data;
|
||||
else (no)
|
||||
:Return error response;
|
||||
stop
|
||||
endif
|
||||
|
||||
if (Check if user is logged in) then (yes)
|
||||
:Retrieve chart view for the user;
|
||||
else (no)
|
||||
:Return error response;
|
||||
stop
|
||||
endif
|
||||
|
||||
:Retrieve indicator data for the user;
|
||||
:Return data response;
|
||||
stop
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
|
@ -1,6 +1,16 @@
|
|||
```plantuml
|
||||
@startuml
|
||||
scale 1
|
||||
|
||||
class "BrighterTrades" {
|
||||
skinparam class {
|
||||
BackgroundColor<<BrighterTrades>> lightblue
|
||||
BackgroundColor<<Config>> lightgreen
|
||||
BackgroundColor<<DataCache>> lightyellow
|
||||
BackgroundColor<<Database>> lightcoral
|
||||
BackgroundColor<<ExchangeInterface>> lightgrey
|
||||
}
|
||||
|
||||
class "BrighterTrades" <<BrighterTrades>> {
|
||||
+ config
|
||||
+ data_cache
|
||||
+ strategies
|
||||
|
|
@ -35,30 +45,146 @@ class "BrighterTrades" {
|
|||
}
|
||||
|
||||
class "app" {
|
||||
+ "index()"
|
||||
+ "ws(socket_conn)"
|
||||
+ "settings()"
|
||||
+ "history()"
|
||||
+ "signup()"
|
||||
+ "signout()"
|
||||
+ "login()"
|
||||
+ "signup_submit()"
|
||||
+ "indicator_init()"
|
||||
+ index()
|
||||
+ ws(socket_conn)
|
||||
+ settings()
|
||||
+ history()
|
||||
+ signup()
|
||||
+ signout()
|
||||
+ login()
|
||||
+ signup_submit()
|
||||
+ indicator_init()
|
||||
}
|
||||
|
||||
class "Flask" {
|
||||
+ "render_template()"
|
||||
+ render_template()
|
||||
}
|
||||
|
||||
"app" --> "index()" : "index()"
|
||||
"app" --> "ws(socket_conn)" : "ws(socket_conn)"
|
||||
"app" --> "settings()" : "settings()"
|
||||
"app" --> "history()" : "history()"
|
||||
"app" --> "signup()" : "signup()"
|
||||
"app" --> "signout()" : "signout()"
|
||||
"app"--> "login()" : "login()"
|
||||
"app" --> "signup_submit()" : "signup_submit()"
|
||||
"app" --> "indicator_init()" : "indicator_init()"
|
||||
class "Users" <<DataCache>> {
|
||||
+ data_cache
|
||||
}
|
||||
|
||||
class "Configuration" <<Config>> {
|
||||
+ exchanges
|
||||
+ indicators
|
||||
+ users
|
||||
+ __init__(exchanges, indicators, users)
|
||||
+ get_exchanges()
|
||||
+ get_indicators()
|
||||
+ get_users()
|
||||
+ add_exchange(exchange)
|
||||
+ remove_exchange(exchange)
|
||||
+ add_indicator(indicator)
|
||||
+ remove_indicator(indicator)
|
||||
+ add_user(user)
|
||||
+ remove_user(user)
|
||||
}
|
||||
|
||||
class "Candles" <<DataCache>> {
|
||||
+ __init__(exchanges, config_obj, database)
|
||||
+ get_last_n_candles(num_candles, asset, timeframe, exchange, user_name)
|
||||
+ set_new_candle(cdata)
|
||||
+ set_cache(symbol=None, interval=None, exchange_name=None, user_name=None)
|
||||
+ get_latestvalues(value_name, symbol, timeframe, exchange, user_name, num_record=1)
|
||||
+ convert_candles(candles)
|
||||
+ get_candle_history(num_records, symbol=None, interval=None, exchange_name=None, user_name=None)
|
||||
}
|
||||
|
||||
class "DataCache" <<DataCache>> {
|
||||
+ db
|
||||
+ get_records_since(key, start_datetime, record_length, ex_details)
|
||||
+ cache_exists(key)
|
||||
+ update_candle_cache(more_records, key)
|
||||
+ get_cached_candles(key)
|
||||
+ set_cached_candles(candles, key)
|
||||
+ clear_cache()
|
||||
+ get_cache_info()
|
||||
+ remove_expired_records()
|
||||
+ remove_cache(key)
|
||||
+ remove_all_caches()
|
||||
}
|
||||
|
||||
class "Database" <<Database>> {
|
||||
+ exchanges
|
||||
+ __init__(exchanges)
|
||||
+ execute_sql(sql)
|
||||
+ get_item_where(item_name, table_name, filter_vals)
|
||||
+ get_rows_where(table, filter_vals)
|
||||
+ insert_dataframe(df, table)
|
||||
+ insert_row(table, columns, values)
|
||||
+ _table_exists(table_name)
|
||||
+ _populate_table(table_name, start_time, ex_details, end_time=None)
|
||||
+ _fetch_exchange_id(exchange_name)
|
||||
+ _fetch_market_id(symbol, exchange_name)
|
||||
+ _insert_candles_into_db(candlesticks, table_name, symbol, exchange_name)
|
||||
+ get_records_since(table_name, st, et, rl, ex_details)
|
||||
+ _get_records(table_name, st, et=None)
|
||||
+ _fetch_candles_from_exchange(symbol, interval, exchange_name, user_name, start_datetime=None, end_datetime=None)
|
||||
+ get_from_static_table(item, table, indexes, create_id=False)
|
||||
}
|
||||
|
||||
class "ExchangeInterface" <<ExchangeInterface>> {
|
||||
+ exchange_data
|
||||
+ available_exchanges
|
||||
--
|
||||
+ __init__()
|
||||
+ connect_exchange(exchange_name, user_name, api_keys=None)
|
||||
+ add_exchange(user_name, _class, arg)
|
||||
+ get_exchange(ename, uname)
|
||||
+ get_connected_exchanges(user_name)
|
||||
+ get_available_exchanges()
|
||||
+ get_exchange_balances(name)
|
||||
+ get_all_balances(name)
|
||||
+ get_order(symbol, order_id, target, user_name)
|
||||
+ get_trade_status(trade, user_name)
|
||||
+ get_trade_executed_qty(trade, user_name)
|
||||
+ get_trade_executed_price(trade, user_name)
|
||||
+ get_price(symbol, price_source=None)
|
||||
}
|
||||
|
||||
class "Indicators" <<DataCache>> {
|
||||
+ get_indicators(user_name)
|
||||
+ get_indicator_data(user_name, source, start_ts, num_results)
|
||||
}
|
||||
|
||||
class "Strategies" <<DataCache>> {
|
||||
+ get_strategies(user_name)
|
||||
+ run_strategy(strategy_name, user_name)
|
||||
}
|
||||
|
||||
class "Backtester" <<DataCache>> {
|
||||
+ run_backtest(strategy_name, user_name)
|
||||
}
|
||||
|
||||
class "Signals" <<Config>> {
|
||||
+ generate_signals(strategy_name, user_name)
|
||||
}
|
||||
|
||||
class "Trades" <<DataCache>> {
|
||||
+ execute_trade(trade_details, user_name)
|
||||
}
|
||||
|
||||
class "HDict" <<Database>> {
|
||||
}
|
||||
|
||||
class "SQLite" <<Database>> {
|
||||
}
|
||||
|
||||
class "shared_utilities" <<Candles>> {
|
||||
}
|
||||
|
||||
class "ArrayList" <<ExchangeInterface>> {
|
||||
}
|
||||
|
||||
app --> "index()" : "index()"
|
||||
app --> "ws(socket_conn)" : "ws(socket_conn)"
|
||||
app --> "settings()" : "settings()"
|
||||
app --> "history()" : "history()"
|
||||
app --> "signup()" : "signup()"
|
||||
app --> "signout()" : "signout()"
|
||||
app --> "login()" : "login()"
|
||||
app --> "signup_submit()" : "signup_submit()"
|
||||
app --> "indicator_init()" : "indicator_init()"
|
||||
|
||||
"signup_submit()" --> "BrighterTrades" : "create_new_user()"
|
||||
"history()" --> "BrighterTrades" : get_user_info()
|
||||
|
|
@ -90,90 +216,6 @@ class "Flask" {
|
|||
"BrighterTrades" -- "SQLite"
|
||||
"BrighterTrades" -- "HDict"
|
||||
|
||||
class "Users" {
|
||||
+ data_cache
|
||||
}
|
||||
|
||||
class "Configuration" {
|
||||
+ exchanges
|
||||
+ indicators
|
||||
+ users
|
||||
+ __init__(exchanges, indicators, users)
|
||||
+ get_exchanges()
|
||||
+ get_indicators()
|
||||
+ get_users()
|
||||
+ add_exchange(exchange)
|
||||
+ remove_exchange(exchange)
|
||||
+ add_indicator(indicator)
|
||||
+ remove_indicator(indicator)
|
||||
+ add_user(user)
|
||||
+ remove_user(user)
|
||||
}
|
||||
|
||||
class "Candles" {
|
||||
+ __init__(exchanges, config_obj, database)
|
||||
+ get_last_n_candles(num_candles, asset, timeframe, exchange, user_name)
|
||||
+ set_new_candle(cdata)
|
||||
+ set_cache(symbol=None, interval=None, exchange_name=None, user_name=None)
|
||||
+ get_latestvalues(value_name, symbol, timeframe, exchange, user_name, num_record=1)
|
||||
+ convert_candles(candles)
|
||||
+ get_candle_history(num_records, symbol=None, interval=None, exchange_name=None, user_name=None)
|
||||
}
|
||||
|
||||
class "DataCache" {
|
||||
+ db
|
||||
+ get_records_since(key, start_datetime, record_length, ex_details)
|
||||
+ cache_exists(key)
|
||||
+ update_candle_cache(more_records, key)
|
||||
+ get_cached_candles(key)
|
||||
+ set_cached_candles(candles, key)
|
||||
+ clear_cache()
|
||||
+ get_cache_info()
|
||||
+ remove_expired_records()
|
||||
+ remove_cache(key)
|
||||
+ remove_all_caches()
|
||||
}
|
||||
|
||||
class "Database" {
|
||||
+ exchanges
|
||||
+ __init__(exchanges)
|
||||
+ execute_sql(sql)
|
||||
+ get_item_where(item_name, table_name, filter_vals)
|
||||
+ get_rows_where(table, filter_vals)
|
||||
+ insert_dataframe(df, table)
|
||||
+ insert_row(table, columns, values)
|
||||
+ _table_exists(table_name)
|
||||
+ _populate_table(table_name, start_time, ex_details, end_time=None)
|
||||
+ _fetch_exchange_id(exchange_name)
|
||||
+ _fetch_market_id(symbol, exchange_name)
|
||||
+ _insert_candles_into_db(candlesticks, table_name, symbol, exchange_name)
|
||||
+ get_records_since(table_name, st, et, rl, ex_details)
|
||||
+ _get_records(table_name, st, et=None)
|
||||
+ _fetch_candles_from_exchange(symbol, interval, exchange_name, user_name, start_datetime=None, end_datetime=None)
|
||||
+ get_from_static_table(item, table, indexes, create_id=False)
|
||||
}
|
||||
|
||||
|
||||
class "ExchangeInterface" {
|
||||
+ exchange_data
|
||||
+ available_exchanges
|
||||
--
|
||||
+ __init__()
|
||||
+ connect_exchange(exchange_name, user_name, api_keys=None)
|
||||
+ add_exchange(user_name, _class, arg)
|
||||
+ get_exchange(ename, uname)
|
||||
+ get_connected_exchanges(user_name)
|
||||
+ get_available_exchanges()
|
||||
+ get_exchange_balances(name)
|
||||
+ get_all_balances(name)
|
||||
+ get_order(symbol, order_id, target, user_name)
|
||||
+ get_trade_status(trade, user_name)
|
||||
+ get_trade_executed_qty(trade, user_name)
|
||||
+ get_trade_executed_price(trade, user_name)
|
||||
+ get_price(symbol, price_source=None)
|
||||
}
|
||||
|
||||
|
||||
"Configuration" -- "Signals"
|
||||
"Configuration" -- "Indicators"
|
||||
"Configuration" -- "Users"
|
||||
|
|
@ -189,9 +231,8 @@ class "ExchangeInterface" {
|
|||
"ExchangeInterface" -- "ArrayList"
|
||||
"ExchangeInterface" -- "DataCache"
|
||||
|
||||
|
||||
|
||||
|
||||
@enduml
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
|
@ -4,6 +4,14 @@
|
|||
|
||||
left to right direction
|
||||
skinparam packageStyle rectangle
|
||||
skinparam usecase {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
RoundCorner 20
|
||||
}
|
||||
title Use Case Low Detail Overview
|
||||
|
||||
actor "User Interface" as User
|
||||
rectangle "Flask App" as App {
|
||||
|
|
@ -33,6 +41,14 @@ rectangle "Flask App" as App {
|
|||
|
||||
left to right direction
|
||||
skinparam packageStyle rectangle
|
||||
skinparam usecase {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
RoundCorner 20
|
||||
}
|
||||
title Use Case Medium Detail Overview
|
||||
|
||||
actor "User Interface" as User
|
||||
rectangle "Flask App" as App {
|
||||
|
|
@ -73,6 +89,14 @@ rectangle "Flask App" as App {
|
|||
|
||||
left to right direction
|
||||
skinparam packageStyle rectangle
|
||||
skinparam usecase {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
RoundCorner 20
|
||||
}
|
||||
title Use Case View Homepage
|
||||
|
||||
actor "User Interface" as User
|
||||
rectangle "Flask App" as App {
|
||||
|
|
@ -106,16 +130,23 @@ rectangle "Flask App" as App {
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Sequence Request Homepage
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
title Sequence Request Homepage
|
||||
|
||||
actor "User Interface" as User
|
||||
participant App as "Flask App"
|
||||
participant BrighterTrades as "BrighterTrades"
|
||||
participant Config as "Config"
|
||||
participant UserStorage as "User Storage"
|
||||
participant "Flask App" as App
|
||||
participant "BrighterTrades" as BrighterTrades
|
||||
participant "Config" as Config
|
||||
participant "User Storage" as UserStorage
|
||||
|
||||
User -> App: Request Homepage
|
||||
App -> BrighterTrades: Create BrighterTrades object
|
||||
|
|
@ -129,13 +160,27 @@ App --> User: Serve Homepage
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Use Case Change Settings:
|
||||
```plantuml
|
||||
@startuml
|
||||
title Use Case Change Settings
|
||||
|
||||
left to right direction
|
||||
skinparam packageStyle rectangle
|
||||
skinparam usecase {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
skinparam actor {
|
||||
BackgroundColor lightgreen
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
FontSize 16
|
||||
}
|
||||
|
||||
actor "User Interface" as User
|
||||
rectangle "Flask App" as App {
|
||||
|
|
@ -153,10 +198,22 @@ rectangle "Flask App" as App {
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Sequence Change Settings
|
||||
```plantuml
|
||||
@startuml
|
||||
title Sequence Change Settings
|
||||
|
||||
skinparam sequence {
|
||||
ActorBackgroundColor lightgreen
|
||||
ParticipantBackgroundColor lightblue
|
||||
ActorBorderColor black
|
||||
ParticipantBorderColor black
|
||||
ActorFontColor darkblue
|
||||
ParticipantFontColor darkblue
|
||||
FontSize 14
|
||||
}
|
||||
|
||||
actor "User Interface" as User
|
||||
participant App as "Flask App"
|
||||
|
|
@ -171,13 +228,18 @@ App --> User: Redirect to Homepage
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Use Case Fetch Candle History:
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
left to right direction
|
||||
skinparam packageStyle rectangle
|
||||
skinparam usecase {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
|
||||
actor "User Interface" as User
|
||||
rectangle "Flask App" as App {
|
||||
|
|
@ -195,10 +257,16 @@ rectangle "Flask App" as App {
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Sequence Request candle history
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
|
||||
actor "User Interface" as User
|
||||
participant App as "Flask App"
|
||||
|
|
@ -215,31 +283,41 @@ App --> User: Serve Candle History
|
|||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Sequence Initialize Indicators:
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
|
||||
actor "User Interface"
|
||||
actor "User Interface" as User
|
||||
|
||||
|
||||
"User Interface" -> app: Requests initialized indicators
|
||||
User -> app: Requests initialized indicators
|
||||
activate app #005500
|
||||
app -> Indicators: initialize indicators
|
||||
activate Indicators #005500
|
||||
Indicators -> app: return initialized indicators
|
||||
deactivate Indicators
|
||||
|
||||
app -> "User Interface": Returns initialized indicators
|
||||
app -> User: Returns initialized indicators
|
||||
deactivate app
|
||||
|
||||
@enduml
|
||||
|
||||
|
||||
```
|
||||
### Sequence Sign in:
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
actor "User Interface"
|
||||
|
||||
"User Interface" -> app: requests "Sign In"
|
||||
|
|
@ -259,7 +337,11 @@ deactivate app
|
|||
### Sequence Sign up:
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
actor "User Interface" as User
|
||||
|
||||
User -> app: send "Sign Up" request
|
||||
|
|
@ -279,7 +361,11 @@ deactivate app
|
|||
### Sequence Sign out:
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
skinparam participant {
|
||||
BackgroundColor lightblue
|
||||
BorderColor black
|
||||
FontColor darkblue
|
||||
}
|
||||
actor "User Interface" as User
|
||||
|
||||
User -> app: send "Sign Out" request
|
||||
55
src/app.py
55
src/app.py
|
|
@ -24,10 +24,19 @@ CORS_HEADERS = 'Content-Type'
|
|||
app.config.from_object(__name__)
|
||||
app.secret_key = '1_BAD_secrete_KEY_is_not_2'
|
||||
|
||||
# Enable cross resources.
|
||||
# Enable cross-origin resource sharing for specific endpoints
|
||||
cors = CORS(app, supports_credentials=True,
|
||||
resources=[r'/api/history', r'/api/indicator_init'],
|
||||
origins=[r'http://127.0.0.1:5000'])
|
||||
resources={
|
||||
r"/api/history": {"origins": ["http://127.0.0.1:5000", "http://localhost:5000"]},
|
||||
r"/api/indicator_init": {"origins": ["http://127.0.0.1:5000", "http://localhost:5000"]}
|
||||
},
|
||||
headers=['Content-Type'])
|
||||
|
||||
|
||||
@app.after_request
|
||||
def add_cors_headers(response):
|
||||
response.headers['Access-Control-Allow-Credentials'] = 'true'
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/')
|
||||
|
|
@ -159,29 +168,37 @@ def settings():
|
|||
|
||||
|
||||
@app.route('/api/history', methods=['POST', 'GET'])
|
||||
# @cross_origin(supports_credentials=True)
|
||||
def history():
|
||||
"""
|
||||
Fetches the candle history of a specific trading pair and timeframe.
|
||||
Currently, set to last 1000 candles.
|
||||
:return: json - price history
|
||||
Fetches the candle history of a specific trading pair and timeframe.
|
||||
Currently, set to last 1000 candles.
|
||||
:return: json - price history
|
||||
"""
|
||||
data = request.get_json()
|
||||
username = data.get('user_name')
|
||||
# Return if the user is not logged in.
|
||||
if not username:
|
||||
return {} # redirect('/')
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
raise ValueError("No JSON data received")
|
||||
|
||||
print('[RECEIVED PRICE HISTORY REQUEST] - user', username)
|
||||
username = data.get('user_name')
|
||||
|
||||
# Get a dictionary of chart attributes from the user data indexed by user_name.
|
||||
chart_view = brighter_trades.get_user_info(user_name=username, info='Chart View')
|
||||
# Return if the user is not logged in.
|
||||
if not username:
|
||||
# redirect('/')
|
||||
return jsonify({'error': 'User not logged in.'}), 401
|
||||
|
||||
payload = brighter_trades.get_market_info(
|
||||
info='Candle History', num_records=1000, chart_view=chart_view, user_name=username)
|
||||
print('[RECEIVED PRICE HISTORY REQUEST] - user', username)
|
||||
|
||||
print('[SENDING PRICE HISTORY TO CLIENT]', payload.tail(2))
|
||||
return jsonify(payload.to_dict('records'))
|
||||
# Get a dictionary of chart attributes from the user data indexed by user_name.
|
||||
chart_view = brighter_trades.get_user_info(user_name=username, info='Chart View')
|
||||
|
||||
payload = brighter_trades.get_market_info(
|
||||
info='Candle History', num_records=1000, chart_view=chart_view, user_name=username)
|
||||
|
||||
print('[SENDING PRICE HISTORY TO CLIENT]', payload.tail(2))
|
||||
return jsonify(payload.to_dict('records')), 200
|
||||
except Exception as e:
|
||||
print(f'Error in history endpoint: {e}')
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
# @app.route('/saved_data')
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ BINANCE_API_KEY = 'rkp1Xflb5nnwt6jys0PG27KXcqwn0q9lKCLryKcSp4mKW2UOlkPRuAHPg45rQ
|
|||
BINANCE_API_SECRET = 'DiFhhYhF64nkPe5f3V7TRJX2bSVA7ZQZlozSdX7O7uYmBMdK985eA6Kp2B2zKvbK'
|
||||
ALPACA_API_KEY = 'PKN0WFYT9VZYUVRBG1HM'
|
||||
ALPACA_API_SECRET = '0C1I6UcBSR2B0SZrBC3DoKGtcglAny8znorvganx'
|
||||
DB_FILE = "C:/Users/Rob/PycharmProjects/BrighterTrading/BrighterTrading.db"
|
||||
DB_FILE = "C:/Users/Rob/PycharmProjects/BrighterTrading/data/BrighterTrading.db"
|
||||
|
|
|
|||
|
|
@ -427,36 +427,35 @@ class Database:
|
|||
quote_volume, num_trades, taker_buy_base_volume, taker_buy_quote_volume]
|
||||
"""
|
||||
|
||||
def fill_data_holes(records):
|
||||
def fill_data_holes(records, interval):
|
||||
time_span = timeframe_to_minutes(interval)
|
||||
last_timestamp = None
|
||||
# Iterate through the timestamps in all the records.
|
||||
for time_stamp in records.open_time:
|
||||
filled_records = []
|
||||
|
||||
for _, row in records.iterrows():
|
||||
time_stamp = row['open_time']
|
||||
|
||||
if last_timestamp is None:
|
||||
# Record this time_stamp.
|
||||
last_timestamp = time_stamp
|
||||
# Skip the first iteration.
|
||||
filled_records.append(row)
|
||||
continue
|
||||
|
||||
# Get the time difference between current and last time_stamps in minutes.
|
||||
delta_ms = time_stamp - last_timestamp
|
||||
delta_minutes = (delta_ms / 1000) / 60
|
||||
# If the difference exceeds the span of a single record.
|
||||
|
||||
if delta_minutes > time_span:
|
||||
# Calculate how many records are missing.
|
||||
num_missing_rec = (delta_minutes / time_span)
|
||||
# Create the missing records
|
||||
num_missing_rec = int(delta_minutes / time_span)
|
||||
step = int(delta_ms / num_missing_rec)
|
||||
# loop from the last timestamp + step until the current timestamp.
|
||||
for ts in range(last_timestamp + step, time_stamp, step):
|
||||
# Copy the current row and append it with all the missing timestamps.
|
||||
row = records.loc[records['open_time'] == time_stamp]
|
||||
row.open_time = ts
|
||||
records = records.append(row, ignore_index=True)
|
||||
# Remember the time_stamp.
|
||||
|
||||
for ts in range(int(last_timestamp) + step, int(time_stamp), step):
|
||||
new_row = row.copy()
|
||||
new_row['open_time'] = ts
|
||||
filled_records.append(new_row)
|
||||
|
||||
filled_records.append(row)
|
||||
last_timestamp = time_stamp
|
||||
return records
|
||||
|
||||
return pd.DataFrame(filled_records)
|
||||
|
||||
# Default start date for fetching from the exchange_name.
|
||||
if start_datetime is None:
|
||||
|
|
@ -494,5 +493,5 @@ class Database:
|
|||
if num_rec_records < estimated_num_records:
|
||||
# Some records may be missing due to server maintenance periods ect.
|
||||
# Fill the holes with copies of the last record received before the gap.
|
||||
candles = fill_data_holes(candles)
|
||||
candles = fill_data_holes(candles, interval)
|
||||
return candles
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
|
|
@ -58,9 +58,9 @@ class Comms {
|
|||
* @returns {Promise<Object|null>} - A promise that resolves
|
||||
* to the fetched price history data, or null if an error occurs.
|
||||
*/
|
||||
async getPriceHistory(userName) {
|
||||
async getPriceHistory(userName) {
|
||||
try {
|
||||
const response = await fetch('http://localhost:5000/api/history', {
|
||||
const response = await fetch('http://127.0.0.1:5000/api/history', {
|
||||
credentials: 'include',
|
||||
mode: 'cors',
|
||||
method: 'POST',
|
||||
|
|
@ -68,6 +68,10 @@ class Comms {
|
|||
body: JSON.stringify({ "user_name": userName })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('Communication[56]: Received candles from the server:');
|
||||
console.log(data);
|
||||
|
|
@ -77,6 +81,7 @@ class Comms {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the Indicator data for a specific user.
|
||||
* @param {string} userName - The name of the user.
|
||||
|
|
@ -31,8 +31,18 @@ class Data {
|
|||
//Request historical price data from the server.
|
||||
this.price_history = this.comms.getPriceHistory(this.user_name);
|
||||
|
||||
//last price from price history.
|
||||
this.price_history.then((value) => { this.last_price = value[value.length-1].close; });
|
||||
// Last price from price history.
|
||||
this.price_history.then((value) => {
|
||||
if (value && value.length > 0) {
|
||||
this.last_price = value[value.length - 1].close;
|
||||
} else {
|
||||
console.error('Received empty price history data');
|
||||
this.last_price = null;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('Error processing price history:', error);
|
||||
this.last_price = null;
|
||||
});
|
||||
|
||||
// Request from the server initialization data for the indicators.
|
||||
this.indicator_data = this.comms.getIndicatorData(this.user_name);
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Loading…
Reference in New Issue