From 0bb9780ff6940dee647663ea5855f7b983750307 Mon Sep 17 00:00:00 2001 From: Rob Date: Fri, 26 Jul 2024 03:52:24 -0300 Subject: [PATCH] Fixed issue with fetching historical data and added missing imports. --- BrighterTrading.db | 0 markdown/App.md | 159 -------- markdown/App/App.md | 375 ++++++++++++++++++ markdown/{ => App}/App_Class_Diagram.md | 255 +++++++----- .../{ => App}/App_UseCase-Seq_Diagrams.md | 110 ++++- src/app.py | 55 ++- src/config.py | 2 +- src/database.py | 37 +- {static => src/static}/Alerts.js | 0 {static => src/static}/Strategies.js | 0 {static => src/static}/arrow-down.svg | 0 {static => src/static}/backtesting.js | 0 {static => src/static}/blue_img.jpg | Bin {static => src/static}/brighterStyles.css | 0 {static => src/static}/charts.js | 0 {static => src/static}/communication.js | 9 +- {static => src/static}/controls.js | 0 {static => src/static}/data.js | 14 +- {static => src/static}/exchanges.js | 0 {static => src/static}/general.js | 0 {static => src/static}/indicators.js | 0 ...ightweight-charts.standalone.production.js | 0 {static => src/static}/signals.js | 0 {static => src/static}/statistics.js | 0 {static => src/static}/trade.js | 0 {static => src/static}/trade_icon.png | Bin {static => src/static}/user.js | 0 {templates => src/templates}/alerts_hud.html | 0 .../templates}/backtesting_hud.html | 0 .../templates}/control_panel.html | 0 .../templates}/edit_indicator_panel.html | 0 .../templates}/exchange_config_popup.html | 0 .../templates}/exchange_info_hud.html | 0 {templates => src/templates}/index.html | 0 .../templates}/indicator_popup.html | 0 .../templates}/indicators_hud.html | 0 {templates => src/templates}/login.html | 0 .../templates}/new_signal_popup.html | 0 .../templates}/new_strategy_popup.html | 0 .../templates}/new_trade_popup.html | 0 {templates => src/templates}/price_chart.html | 0 {templates => src/templates}/sign_up.html | 0 {templates => src/templates}/signals_hud.html | 0 .../templates}/statistics_hud.html | 0 .../templates}/strategies_hud.html | 0 .../templates}/trade_details_popup.html | 0 {templates => src/templates}/trading_hud.html | 0 47 files changed, 695 insertions(+), 321 deletions(-) create mode 100644 BrighterTrading.db delete mode 100644 markdown/App.md create mode 100644 markdown/App/App.md rename markdown/{ => App}/App_Class_Diagram.md (73%) rename markdown/{ => App}/App_UseCase-Seq_Diagrams.md (77%) rename {static => src/static}/Alerts.js (100%) rename {static => src/static}/Strategies.js (100%) rename {static => src/static}/arrow-down.svg (100%) rename {static => src/static}/backtesting.js (100%) rename {static => src/static}/blue_img.jpg (100%) rename {static => src/static}/brighterStyles.css (100%) rename {static => src/static}/charts.js (100%) rename {static => src/static}/communication.js (97%) rename {static => src/static}/controls.js (100%) rename {static => src/static}/data.js (82%) rename {static => src/static}/exchanges.js (100%) rename {static => src/static}/general.js (100%) rename {static => src/static}/indicators.js (100%) rename {static => src/static}/lightweight-charts.standalone.production.js (100%) rename {static => src/static}/signals.js (100%) rename {static => src/static}/statistics.js (100%) rename {static => src/static}/trade.js (100%) rename {static => src/static}/trade_icon.png (100%) rename {static => src/static}/user.js (100%) rename {templates => src/templates}/alerts_hud.html (100%) rename {templates => src/templates}/backtesting_hud.html (100%) rename {templates => src/templates}/control_panel.html (100%) rename {templates => src/templates}/edit_indicator_panel.html (100%) rename {templates => src/templates}/exchange_config_popup.html (100%) rename {templates => src/templates}/exchange_info_hud.html (100%) rename {templates => src/templates}/index.html (100%) rename {templates => src/templates}/indicator_popup.html (100%) rename {templates => src/templates}/indicators_hud.html (100%) rename {templates => src/templates}/login.html (100%) rename {templates => src/templates}/new_signal_popup.html (100%) rename {templates => src/templates}/new_strategy_popup.html (100%) rename {templates => src/templates}/new_trade_popup.html (100%) rename {templates => src/templates}/price_chart.html (100%) rename {templates => src/templates}/sign_up.html (100%) rename {templates => src/templates}/signals_hud.html (100%) rename {templates => src/templates}/statistics_hud.html (100%) rename {templates => src/templates}/strategies_hud.html (100%) rename {templates => src/templates}/trade_details_popup.html (100%) rename {templates => src/templates}/trading_hud.html (100%) diff --git a/BrighterTrading.db b/BrighterTrading.db new file mode 100644 index 0000000..e69de29 diff --git a/markdown/App.md b/markdown/App.md deleted file mode 100644 index 6d2114a..0000000 --- a/markdown/App.md +++ /dev/null @@ -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 -``` diff --git a/markdown/App/App.md b/markdown/App/App.md new file mode 100644 index 0000000..980e493 --- /dev/null +++ b/markdown/App/App.md @@ -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 +———————————————————————————————— +=app.py +———————————————————————————————— + 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 +———————————————————————————————— +=/index +———————————————————————————————— + 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 +———————————————————————————————— +=/ws +———————————————————————————————— + 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 +———————————————————————————————— +=/settings +———————————————————————————————— + 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 +———————————————————————— +=/history​ +———————————————————————— + 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 +———————————————————————————————— +=/signup +———————————————————————————————— +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 +———————————————————————————————— +=/signout +———————————————————————————————— + 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 +———————————————————————————————— +=/login +———————————————————————————————— + 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 +———————————————————————————————— +=/signup_submit +———————————————————————————————— + 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 +———————————————————————————————— +=/indicator_init +———————————————————————————————— + 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 + +``` diff --git a/markdown/App_Class_Diagram.md b/markdown/App/App_Class_Diagram.md similarity index 73% rename from markdown/App_Class_Diagram.md rename to markdown/App/App_Class_Diagram.md index ebc0119..f990dfd 100644 --- a/markdown/App_Class_Diagram.md +++ b/markdown/App/App_Class_Diagram.md @@ -1,6 +1,16 @@ ```plantuml +@startuml +scale 1 -class "BrighterTrades" { +skinparam class { + BackgroundColor<> lightblue + BackgroundColor<> lightgreen + BackgroundColor<> lightyellow + BackgroundColor<> lightcoral + BackgroundColor<> lightgrey +} + +class "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" <> { + + 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) +} + +class "Indicators" <> { + + get_indicators(user_name) + + get_indicator_data(user_name, source, start_ts, num_results) +} + +class "Strategies" <> { + + get_strategies(user_name) + + run_strategy(strategy_name, user_name) +} + +class "Backtester" <> { + + run_backtest(strategy_name, user_name) +} + +class "Signals" <> { + + generate_signals(strategy_name, user_name) +} + +class "Trades" <> { + + execute_trade(trade_details, user_name) +} + +class "HDict" <> { +} + +class "SQLite" <> { +} + +class "shared_utilities" <> { +} + +class "ArrayList" <> { +} + +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 + + ``` \ No newline at end of file diff --git a/markdown/App_UseCase-Seq_Diagrams.md b/markdown/App/App_UseCase-Seq_Diagrams.md similarity index 77% rename from markdown/App_UseCase-Seq_Diagrams.md rename to markdown/App/App_UseCase-Seq_Diagrams.md index e097e54..1ab5eab 100644 --- a/markdown/App_UseCase-Seq_Diagrams.md +++ b/markdown/App/App_UseCase-Seq_Diagrams.md @@ -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 diff --git a/src/app.py b/src/app.py index 03fa4b1..758de9c 100644 --- a/src/app.py +++ b/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') diff --git a/src/config.py b/src/config.py index 10a7ca3..6ca7103 100644 --- a/src/config.py +++ b/src/config.py @@ -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" diff --git a/src/database.py b/src/database.py index 9298383..0f3892b 100644 --- a/src/database.py +++ b/src/database.py @@ -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 diff --git a/static/Alerts.js b/src/static/Alerts.js similarity index 100% rename from static/Alerts.js rename to src/static/Alerts.js diff --git a/static/Strategies.js b/src/static/Strategies.js similarity index 100% rename from static/Strategies.js rename to src/static/Strategies.js diff --git a/static/arrow-down.svg b/src/static/arrow-down.svg similarity index 100% rename from static/arrow-down.svg rename to src/static/arrow-down.svg diff --git a/static/backtesting.js b/src/static/backtesting.js similarity index 100% rename from static/backtesting.js rename to src/static/backtesting.js diff --git a/static/blue_img.jpg b/src/static/blue_img.jpg similarity index 100% rename from static/blue_img.jpg rename to src/static/blue_img.jpg diff --git a/static/brighterStyles.css b/src/static/brighterStyles.css similarity index 100% rename from static/brighterStyles.css rename to src/static/brighterStyles.css diff --git a/static/charts.js b/src/static/charts.js similarity index 100% rename from static/charts.js rename to src/static/charts.js diff --git a/static/communication.js b/src/static/communication.js similarity index 97% rename from static/communication.js rename to src/static/communication.js index e5f5f10..8aaba68 100644 --- a/static/communication.js +++ b/src/static/communication.js @@ -58,9 +58,9 @@ class Comms { * @returns {Promise} - 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. diff --git a/static/controls.js b/src/static/controls.js similarity index 100% rename from static/controls.js rename to src/static/controls.js diff --git a/static/data.js b/src/static/data.js similarity index 82% rename from static/data.js rename to src/static/data.js index 84178a8..a62215a 100644 --- a/static/data.js +++ b/src/static/data.js @@ -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); diff --git a/static/exchanges.js b/src/static/exchanges.js similarity index 100% rename from static/exchanges.js rename to src/static/exchanges.js diff --git a/static/general.js b/src/static/general.js similarity index 100% rename from static/general.js rename to src/static/general.js diff --git a/static/indicators.js b/src/static/indicators.js similarity index 100% rename from static/indicators.js rename to src/static/indicators.js diff --git a/static/lightweight-charts.standalone.production.js b/src/static/lightweight-charts.standalone.production.js similarity index 100% rename from static/lightweight-charts.standalone.production.js rename to src/static/lightweight-charts.standalone.production.js diff --git a/static/signals.js b/src/static/signals.js similarity index 100% rename from static/signals.js rename to src/static/signals.js diff --git a/static/statistics.js b/src/static/statistics.js similarity index 100% rename from static/statistics.js rename to src/static/statistics.js diff --git a/static/trade.js b/src/static/trade.js similarity index 100% rename from static/trade.js rename to src/static/trade.js diff --git a/static/trade_icon.png b/src/static/trade_icon.png similarity index 100% rename from static/trade_icon.png rename to src/static/trade_icon.png diff --git a/static/user.js b/src/static/user.js similarity index 100% rename from static/user.js rename to src/static/user.js diff --git a/templates/alerts_hud.html b/src/templates/alerts_hud.html similarity index 100% rename from templates/alerts_hud.html rename to src/templates/alerts_hud.html diff --git a/templates/backtesting_hud.html b/src/templates/backtesting_hud.html similarity index 100% rename from templates/backtesting_hud.html rename to src/templates/backtesting_hud.html diff --git a/templates/control_panel.html b/src/templates/control_panel.html similarity index 100% rename from templates/control_panel.html rename to src/templates/control_panel.html diff --git a/templates/edit_indicator_panel.html b/src/templates/edit_indicator_panel.html similarity index 100% rename from templates/edit_indicator_panel.html rename to src/templates/edit_indicator_panel.html diff --git a/templates/exchange_config_popup.html b/src/templates/exchange_config_popup.html similarity index 100% rename from templates/exchange_config_popup.html rename to src/templates/exchange_config_popup.html diff --git a/templates/exchange_info_hud.html b/src/templates/exchange_info_hud.html similarity index 100% rename from templates/exchange_info_hud.html rename to src/templates/exchange_info_hud.html diff --git a/templates/index.html b/src/templates/index.html similarity index 100% rename from templates/index.html rename to src/templates/index.html diff --git a/templates/indicator_popup.html b/src/templates/indicator_popup.html similarity index 100% rename from templates/indicator_popup.html rename to src/templates/indicator_popup.html diff --git a/templates/indicators_hud.html b/src/templates/indicators_hud.html similarity index 100% rename from templates/indicators_hud.html rename to src/templates/indicators_hud.html diff --git a/templates/login.html b/src/templates/login.html similarity index 100% rename from templates/login.html rename to src/templates/login.html diff --git a/templates/new_signal_popup.html b/src/templates/new_signal_popup.html similarity index 100% rename from templates/new_signal_popup.html rename to src/templates/new_signal_popup.html diff --git a/templates/new_strategy_popup.html b/src/templates/new_strategy_popup.html similarity index 100% rename from templates/new_strategy_popup.html rename to src/templates/new_strategy_popup.html diff --git a/templates/new_trade_popup.html b/src/templates/new_trade_popup.html similarity index 100% rename from templates/new_trade_popup.html rename to src/templates/new_trade_popup.html diff --git a/templates/price_chart.html b/src/templates/price_chart.html similarity index 100% rename from templates/price_chart.html rename to src/templates/price_chart.html diff --git a/templates/sign_up.html b/src/templates/sign_up.html similarity index 100% rename from templates/sign_up.html rename to src/templates/sign_up.html diff --git a/templates/signals_hud.html b/src/templates/signals_hud.html similarity index 100% rename from templates/signals_hud.html rename to src/templates/signals_hud.html diff --git a/templates/statistics_hud.html b/src/templates/statistics_hud.html similarity index 100% rename from templates/statistics_hud.html rename to src/templates/statistics_hud.html diff --git a/templates/strategies_hud.html b/src/templates/strategies_hud.html similarity index 100% rename from templates/strategies_hud.html rename to src/templates/strategies_hud.html diff --git a/templates/trade_details_popup.html b/src/templates/trade_details_popup.html similarity index 100% rename from templates/trade_details_popup.html rename to src/templates/trade_details_popup.html diff --git a/templates/trading_hud.html b/src/templates/trading_hud.html similarity index 100% rename from templates/trading_hud.html rename to src/templates/trading_hud.html