From 5f2472a11f8617681efa552e5b1f70dda7608f2b Mon Sep 17 00:00:00 2001 From: TBS093A Date: Thu, 7 May 2020 09:10:05 +0200 Subject: [PATCH] init repository --- TradeApp/__init__.py | 0 TradeApp/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 150 bytes TradeApp/__pycache__/routing.cpython-36.pyc | Bin 0 -> 403 bytes TradeApp/__pycache__/settings.cpython-36.pyc | Bin 0 -> 2586 bytes TradeApp/__pycache__/urls.cpython-36.pyc | Bin 0 -> 1015 bytes TradeApp/__pycache__/wsgi.cpython-36.pyc | Bin 0 -> 555 bytes TradeApp/routing.py | 12 + TradeApp/settings.py | 144 +++++++ TradeApp/urls.py | 23 ++ TradeApp/wsgi.py | 16 + chat/__init__.py | 0 chat/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 146 bytes chat/__pycache__/admin.cpython-36.pyc | Bin 0 -> 252 bytes chat/__pycache__/apps.cpython-36.pyc | Bin 0 -> 358 bytes chat/__pycache__/consumers.cpython-36.pyc | Bin 0 -> 1782 bytes chat/__pycache__/models.cpython-36.pyc | Bin 0 -> 1178 bytes chat/__pycache__/routing.cpython-36.pyc | Bin 0 -> 307 bytes chat/__pycache__/urls.cpython-36.pyc | Bin 0 -> 304 bytes chat/__pycache__/views.cpython-36.pyc | Bin 0 -> 684 bytes chat/admin.py | 4 + chat/consumers.py | 61 +++ chat/migrations/0001_initial.py | 22 ++ chat/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-36.pyc | Bin 0 -> 674 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 157 bytes chat/models.py | 25 ++ chat/routing.py | 7 + chat/urls.py | 8 + chat/views.py | 18 + db.sqlite3 | Bin 0 -> 253952 bytes generalApp/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 152 bytes generalApp/__pycache__/admin.cpython-36.pyc | Bin 0 -> 433 bytes generalApp/__pycache__/apps.cpython-36.pyc | Bin 0 -> 376 bytes .../__pycache__/exchangeVO.cpython-36.pyc | Bin 0 -> 4338 bytes generalApp/__pycache__/methods.cpython-36.pyc | Bin 0 -> 6133 bytes generalApp/__pycache__/models.cpython-36.pyc | Bin 0 -> 14597 bytes generalApp/__pycache__/session.cpython-36.pyc | Bin 0 -> 701 bytes generalApp/__pycache__/urls.cpython-36.pyc | Bin 0 -> 1169 bytes .../__pycache__/utilities.cpython-36.pyc | Bin 0 -> 3810 bytes generalApp/__pycache__/utils.cpython-36.pyc | Bin 0 -> 886 bytes generalApp/__pycache__/views.cpython-36.pyc | Bin 0 -> 4941 bytes generalApp/admin.py | 14 + generalApp/apps.py | 5 + generalApp/exchangeVO.py | 122 ++++++ generalApp/methods.py | 166 +++++++++ generalApp/migrations/0001_initial.py | 110 ++++++ generalApp/migrations/0002_triggers_status.py | 18 + .../migrations/0003_auto_20191229_1407.py | 18 + generalApp/migrations/0004_notifications.py | 25 ++ generalApp/migrations/0005_users_avatar.py | 18 + .../migrations/0006_auto_20200113_2147.py | 18 + .../migrations/0007_auto_20200115_1743.py | 18 + generalApp/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-36.pyc | Bin 0 -> 2039 bytes .../0002_triggers_status.cpython-36.pyc | Bin 0 -> 591 bytes .../0003_auto_20191229_1407.cpython-36.pyc | Bin 0 -> 613 bytes .../0004_notifications.cpython-36.pyc | Bin 0 -> 876 bytes .../0005_users_avatar.cpython-36.pyc | Bin 0 -> 608 bytes .../0006_auto_20200113_2147.cpython-36.pyc | Bin 0 -> 599 bytes .../0007_auto_20200115_1743.cpython-36.pyc | Bin 0 -> 606 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 163 bytes generalApp/models.py | 350 ++++++++++++++++++ generalApp/tests.py | 3 + generalApp/urls.py | 30 ++ generalApp/utilities.py | 121 ++++++ generalApp/views.py | 179 +++++++++ manage.py | 21 ++ run.sh | 4 + testGraph.txt | 1 + testGraph2.txt | 1 + 71 files changed, 1582 insertions(+) create mode 100644 TradeApp/__init__.py create mode 100644 TradeApp/__pycache__/__init__.cpython-36.pyc create mode 100644 TradeApp/__pycache__/routing.cpython-36.pyc create mode 100644 TradeApp/__pycache__/settings.cpython-36.pyc create mode 100644 TradeApp/__pycache__/urls.cpython-36.pyc create mode 100644 TradeApp/__pycache__/wsgi.cpython-36.pyc create mode 100644 TradeApp/routing.py create mode 100644 TradeApp/settings.py create mode 100644 TradeApp/urls.py create mode 100644 TradeApp/wsgi.py create mode 100644 chat/__init__.py create mode 100644 chat/__pycache__/__init__.cpython-36.pyc create mode 100644 chat/__pycache__/admin.cpython-36.pyc create mode 100644 chat/__pycache__/apps.cpython-36.pyc create mode 100644 chat/__pycache__/consumers.cpython-36.pyc create mode 100644 chat/__pycache__/models.cpython-36.pyc create mode 100644 chat/__pycache__/routing.cpython-36.pyc create mode 100644 chat/__pycache__/urls.cpython-36.pyc create mode 100644 chat/__pycache__/views.cpython-36.pyc create mode 100644 chat/admin.py create mode 100644 chat/consumers.py create mode 100644 chat/migrations/0001_initial.py create mode 100644 chat/migrations/__init__.py create mode 100644 chat/migrations/__pycache__/0001_initial.cpython-36.pyc create mode 100644 chat/migrations/__pycache__/__init__.cpython-36.pyc create mode 100644 chat/models.py create mode 100644 chat/routing.py create mode 100644 chat/urls.py create mode 100644 chat/views.py create mode 100644 db.sqlite3 create mode 100644 generalApp/__init__.py create mode 100644 generalApp/__pycache__/__init__.cpython-36.pyc create mode 100644 generalApp/__pycache__/admin.cpython-36.pyc create mode 100644 generalApp/__pycache__/apps.cpython-36.pyc create mode 100644 generalApp/__pycache__/exchangeVO.cpython-36.pyc create mode 100644 generalApp/__pycache__/methods.cpython-36.pyc create mode 100644 generalApp/__pycache__/models.cpython-36.pyc create mode 100644 generalApp/__pycache__/session.cpython-36.pyc create mode 100644 generalApp/__pycache__/urls.cpython-36.pyc create mode 100644 generalApp/__pycache__/utilities.cpython-36.pyc create mode 100644 generalApp/__pycache__/utils.cpython-36.pyc create mode 100644 generalApp/__pycache__/views.cpython-36.pyc create mode 100644 generalApp/admin.py create mode 100644 generalApp/apps.py create mode 100644 generalApp/exchangeVO.py create mode 100644 generalApp/methods.py create mode 100644 generalApp/migrations/0001_initial.py create mode 100644 generalApp/migrations/0002_triggers_status.py create mode 100644 generalApp/migrations/0003_auto_20191229_1407.py create mode 100644 generalApp/migrations/0004_notifications.py create mode 100644 generalApp/migrations/0005_users_avatar.py create mode 100644 generalApp/migrations/0006_auto_20200113_2147.py create mode 100644 generalApp/migrations/0007_auto_20200115_1743.py create mode 100644 generalApp/migrations/__init__.py create mode 100644 generalApp/migrations/__pycache__/0001_initial.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0002_triggers_status.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0003_auto_20191229_1407.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0004_notifications.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0005_users_avatar.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0006_auto_20200113_2147.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/0007_auto_20200115_1743.cpython-36.pyc create mode 100644 generalApp/migrations/__pycache__/__init__.cpython-36.pyc create mode 100644 generalApp/models.py create mode 100644 generalApp/tests.py create mode 100644 generalApp/urls.py create mode 100644 generalApp/utilities.py create mode 100644 generalApp/views.py create mode 100755 manage.py create mode 100755 run.sh create mode 100644 testGraph.txt create mode 100644 testGraph2.txt diff --git a/TradeApp/__init__.py b/TradeApp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/TradeApp/__pycache__/__init__.cpython-36.pyc b/TradeApp/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f32829191190dfe8fe45964ce0d3cbc611468387 GIT binary patch literal 150 zcmXr!<>d-j+7inE1dl-k3@`#24nSPY0whuxf*CX!{Z=v*frJsnFK7LX{M=Oi{M1~1 zm;CI~+|<01O8tPM{H)aEl4AXkqQsO`$ASVZjQIG>yv&mLc)fzkTO2mI`6;D2sdga4 Ii-DK{0Qv$YCjbBd literal 0 HcmV?d00001 diff --git a/TradeApp/__pycache__/routing.cpython-36.pyc b/TradeApp/__pycache__/routing.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6329646fe4d1786a37299a9aa5a1e22f30039bb3 GIT binary patch literal 403 zcmZutO-lnY5KXe_r!5r4AF-G2!K;WBZ+;+c1qrC6o560IY(h3m>AAngzm%&d|AHrH zwG)t7&nMp)qxZpoJ(Jj%2 zL~)?Np}p#?x;wg~1(xWkWJc1~C#H~;#*;}MmUo3x8aC3yEXaJFvUvR9ZLqo3^R0ua ztpoVjdz{|>()-xkz@oDG8baC^!+a^r5_C0|80Hx!$I-#_*jMtq4Rlff4h6X-933@db+%D^w&pqCX@L)llm*; z`ZYf6Uz{LAGLVIwoh4bCJGL=xCYZO zW0px7uEQ+cfSYg&=HNEmfg5ItOd;wT+$Ga6Z)QM%dvG5fz(e@X6s#P^I4&`@VNb zyId-lH>pc~gHsUqPsPWOfL0A~ELUXQ@cB^lu^2EkBMz;uOY72eM88F&j^|U+a?!qH zaLaQ={O3IjJz6&X2?L_^c5>5(+t-u-U98?6JvGJ`M6{+9iOiB z_bc|JC3a%+l~12uE*>uSoQ+58%OCmT$tpiS2|A=~CJfq0D-pUqgNJj26G~mr<-WBq zC2WSb#-#!8g%8GrF@(CDpY|yW?~ZLU${6x{al^q4!$idWaRkSVbmKfQGS&5b)}vSe zJ|jg8)OD%N!qp+fu>fp5x=$rWyMb@w%6^~IP218GVdSMWPBWOb8TO996t8+*1PokTir%x#wF$l2Y=&xN7QXt?vd&kmYoJokJ?lUe9VwMw85#D zeT4Uq9eb>cC&rM%C*wvg>PSHM12bH?f~HT8vEO+3bf|k) z>2b0yu^cBc9C0yHK1hzf6%>N~YrBSNj-)}o@av!f@gLTjf}Z#A{>-Wgvf z%(Nt<-^UClZ+EuE!T1ar$Jql_s;RZ zT@^p*tDRwt=LTM1)j%_FsBd*IT6lQIw(kY;t0hf%xIDU8bf1F7uo&<{X~)az;Kpef zr_?8tJ&$qrt+clOLVAW{?dw1DnM@_;=a6rbueO?R>zm;ubyovMCU!g3uqfl}2-{vp zr6MZ%C7db`qJpmDTSeESoW~-eZ}1)_-SS=R+NfacvqVzV_4pFhby9qzXlh(PQCU-~ zZMCDnQ$IwLHTBKzW;Crd8m&FGrf;>hjuy?-n_34&D8QoAqVjgVR%@txN?RqjtF5-C zx7u~A6+MB)b9AlUYIXG8b|XGPRO+bPI}N3yYSHYTwpowOH0o6)F55^r^ei_j)s&7B z$D~E`%5G;%-%&Jeuhp*U@0CU!H_;85RmQ+%rn;pxn`%REC?8bpis^>Z+}u?*RlVA( zspz=At?HzOWnA3F^VZj1HV3Q5+OuYqk7XT#6m&3_Y8>yM8Gj*WHJ-jz<(}tI*`tnJ z^Nz3(Tz)F=41O{&d6fT47Nb|U)IW`izd9ZSHhndPCRqVC4S;8%bT0 literal 0 HcmV?d00001 diff --git a/TradeApp/__pycache__/urls.cpython-36.pyc b/TradeApp/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c586871cd0f2a62848de1403b884c1b9db4210e GIT binary patch literal 1015 zcma)5U2oGc6iw2kAKAwE34UuMjaZDgimz!fF=;{*3<>pt&W&%|l-Lfo16yDBYxqlf z6-blH{UP+KvgCYbA)doiY@*N$%7ixAl!=6tJTZ zkD}P+XgEA-buE>EBO;lA7ef~hllZh?#ypv!FusHOKNiX^K|3O8W7L+;JH%?(Kah>9 zPnnrIkWum%qjQ-R70=}YO=$W#X&GMT)}Qmn7=l#rdR#4x5;AYC9B=H}Tu15*-;!)= zj~Y`R%yw3&1w{k5orW&a;0}`{zQ;NC62FcZ7r9J=I&_ZLy|#MY%_WB$x;|Wh1kDPZ z&F1Vn%9hO1^}zi$nQj9?-zS5*H=W{4O{bGbtqfFebw1NL;$FSCqfO%r^K|Iap~)@O zp;KJ%?M%T>PsgsvZNFbpckNVxpl{UIN`SPt^l~$_hHjtFKLQ7vmbZ2Pxlp_+;N>C0 P8HXAA`~Kt3KJI@21*|+; literal 0 HcmV?d00001 diff --git a/TradeApp/__pycache__/wsgi.cpython-36.pyc b/TradeApp/__pycache__/wsgi.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7609f031b59260061e9f4bb1445096cb4fce83f8 GIT binary patch literal 555 zcmZutO=}x55Y=j(*le59K*?F;W@uL>y_M1?;MBOZPQfk#Ls_e<@mj9FSjkSDYfk+s zz4ylyU32PR=&4#8gAWzxX{6D-_hw!l9c9<2zrOxR5PCp+D~<7a-0o!rjwXmF9Lr>q z#50vxrIR#4kStn@1K#2X_c-3tdo(%Zc!au#cfYgiQGY;6qi3QbGgFgs%{W|GOKfcx zQ2IQ}2A;sJH4Yr{b0FIaCMEkOfiOoHQHC!iypXU0Nmi^Do0Mh>IGIkFwNjMK3!|sg z$oD?VC{qIwIx4D7f*2jig(EW|;W=>t+1z{UUQ^0V>2khcx-vUYrBM_#Jdjango views is added by default) + 'websocket': AuthMiddlewareStack( + URLRouter( + chat.routing.websocket_urlpatterns + ) + ), +}) \ No newline at end of file diff --git a/TradeApp/settings.py b/TradeApp/settings.py new file mode 100644 index 0000000..b656752 --- /dev/null +++ b/TradeApp/settings.py @@ -0,0 +1,144 @@ +""" +Django settings for TradeApp project. + +Generated by 'django-admin startproject' using Django 2.2.6. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.2/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = ')o!ecewa-#m^$l$qy*pb)l&$swgt*xx8#j#hm3&2%^t#w-tqwu' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'generalApp', + 'chat', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'corsheaders', + 'channels' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.common.BrokenLinkEmailsMiddleware', + 'django.middleware.common.CommonMiddleware', +] + +CORS_ORIGIN_ALLOW_ALL = True + +# CORS_ORIGIN_ALLOW_ALL = False +# +# CORS_ORIGIN_WHITELIST = ( +# 'http//:localhost:8000', +# ) + +ROOT_URLCONF = 'TradeApp.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'TradeApp.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/2.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + +# Password validation +# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Routing for channels websocket + +ASGI_APPLICATION = "TradeApp.routing.application" +CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + "hosts": [('127.0.0.1', 6379)], + }, + }, +} + +# Internationalization +# https://docs.djangoproject.com/en/2.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.2/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/TradeApp/urls.py b/TradeApp/urls.py new file mode 100644 index 0000000..e9a2ff1 --- /dev/null +++ b/TradeApp/urls.py @@ -0,0 +1,23 @@ +"""TradeApp URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('index/', include('generalApp.urls')), + path('chat/', include('chat.urls')), + path('admin/', admin.site.urls), +] diff --git a/TradeApp/wsgi.py b/TradeApp/wsgi.py new file mode 100644 index 0000000..214083e --- /dev/null +++ b/TradeApp/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for TradeApp project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TradeApp.settings') + +application = get_wsgi_application() diff --git a/chat/__init__.py b/chat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chat/__pycache__/__init__.cpython-36.pyc b/chat/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..563a8542a9c4e512888324ea1da214b97736d955 GIT binary patch literal 146 zcmXr!<>iVFPl{szg2x~N1{i@12OutH0TL+;!3>&=ek&P@K*9*(m%V;Qer~FMerm41 zOMZ4~ZfaghrG7wBepYI7NwI!NQDRD}V?hCek(`lOq8}fhnU`4-AFo$Xd5gm)H$SB` NC)EyQa4`@w002-{BbopJ literal 0 HcmV?d00001 diff --git a/chat/__pycache__/admin.cpython-36.pyc b/chat/__pycache__/admin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99a77071c8f3316d8879680c3df655d4ce9e2caf GIT binary patch literal 252 zcmYLDF>1p=5Zsk@MhUiG;YKceMOqVLNEt$KR2UToNw?TibUJZ&E>!0=0k{6lwW;)l zR6f}dFU&Bz472kzoj#tor`-ksem(vt@ao0G%smMZScAkA5kw$Hb&vpIHL5~l-@`5Z zgqZc-2{AgB30XEh-Zosk$K!M+s;t?oWuY3Y%UlofZY-6c+PKh^mRzK1Um8o=u{V|H z-4Eyo@4C|8iXW6Du1NA%^>vig*p7c_RZ(FLPjn_|-L`j895TzVJ(g|fqLu%2tm%2^ KWI|69jDic#t3u2G literal 0 HcmV?d00001 diff --git a/chat/__pycache__/apps.cpython-36.pyc b/chat/__pycache__/apps.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..964a36f8c25e00650fde3e649b0836bdce66354b GIT binary patch literal 358 zcmYLEy-ve05I)C7N<%C02&`G^ff0m?io{kS6$vRwSZ>a=lsFD?GIWNQ;gzy7@d`{m zC(xdB-+lIXzZa89^7OcRUIM^3`N0IS8M!|vKtNW2Wf@~|2N)s$1muQ&@GL^Hg!JTx zvLI#M=%%XXu6%i2=i%qy7?BydKO-=ZF$Ah)8OMmKd6&#Lx*6&+krQ8}qKlO(wKYn0 ziBi^KTLeB<>b=#)pCUs1f;y(YJ^WtEjk88NW96-TYpp4poxHEz*5r+s54A=^J03}x zCUsT$X|=04wF#H|h#+SDdqMl1;#QYyHw}4p(0b)KbzmbBy7+2X^*Y?#_Zjm&@3K=e literal 0 HcmV?d00001 diff --git a/chat/__pycache__/consumers.cpython-36.pyc b/chat/__pycache__/consumers.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a8487c25f622ed4143f5ba2c4b1821506ab9507 GIT binary patch literal 1782 zcmZuyOK%%D5awfFT1(CYZXKuS3+QEmR07gdi=uGhphbZ|4Vtt87Hx_3l9ny)Lm??A z3gnY==q10P?GI?tU&L!q`3pUDhHEQ!kQF!_lEdNfn{TMk27~mwpa1#weoV-}T zb%Vkzn^M?TU=I^F9;-vsmNR7!+QuwurN^&mXB*yc4-c0m?!5RIDErXN9T1A-RFa%Y zD%lH?bID}@J;Wj-=tCLH1o}w!AcEBO4~~n?Atj!HAKsHgJAh{X2C*Vjxa}U?5*puw zv7j=5S^7Kqlfj6|@QgnD!t!Y_4cFuz`Q^?TTd`?`HZ!L0f*#9gm#mnG!75p?HR2YZ z(Ff$o-N$4_We9e^S-vJ`9Cxj_h-3t^v*&1Ud$5vDx7HMTICt7#Gm6m-)&!A9RL8Ej z(3Q~b!YUWdo)&syTu--cEt;ZMd04`g#Wxx+`6%0Vp()$B(mfcuYu;=Ed*|L*hd3Lz zhf`Hr<9Jb3E1BZE=s&Ien^!KU4DXrh4lIKa7kZMPlQ0STbTR+h!9AQlmM%+qd}8`9(B5n zA)U#z=Tn@5zJ)3FsSU;%)!X3T=T7^I==&7uKFm5kQP$^CU&CP}RiyyD>$n4B)i*%o zgDxrZ#FT}WdJ7kBg2=eu!S%GPTBAhSN|oPS%w=Jf&-3?3KSIilPedo)1#_38qYl## zVQla;!Vt}r_F0GE^W7`>z232b5Xp#K^A(46j1aEq+Jkq-Epi=d%Yzb1s13>fU>jig z*z?PZS{YMJRK{FjmviOfi;2huQ`0sM*i}e#35~Qv!>Fc%A`3hUu4mOVE8y})zP(We z`q1w~cyFQ*YgMX~Q}rpV8B7L2Dj|Isqi@jX+;nsIEA;sQw!&KgZw=4}ULA`>g117l zm;RlF3g=@V0&w9YFwQvE5JZnVT__jz+?=PlbEnqSet5{|kJg^4ky$zA9!oQH|0kL*nb{e8=9`D__WR+l$3H)QWrX}D7nTe1CTw*d2q&Bt zq@)R@D6@ipFb8qP+K6l=d*gt{0B&OOgYc2`}QuM5Cn>Ru= zb*02`jP~>8fUpT$ArT~@oFq&*xyvbMUufci>@P{u;SP6?ND^?5`@p-r!vo+U@A43M zkM|&Uq`epQXtaNF8@xf_u*~+-LR6D>I;Nn)h1`R^4O^`PS&*C@L$1K-8E41jy9fT* z@RZ((9nEH3yH!>S-JL5Tx9fS;f_qnq;?oZzBk*$ia4@Y)F{nj3*r`9yOHsA^gV(ao z#kf_2cQWH*t7-lT<7w6oY>76Secee@)yg#OA}r_&06plNWH!z$W1|HFa@;0^>mXnT zIbG1D=@j6m! zrd!&{ibDHY(};@88{kvBxvDGe@p;*(*tK=++T&Yr)-7hL)pYM_CM)3Rm34|4t${0r zl^`^Pj6%9f57ul}mk$nMl%an(a?rmpO<_>x15X7!2-8q3`iZ@L2lyjy6C7M8sRB#4dg&^wi zH7I#HP=k9G4|k+zG4Br$vNreCj{o$Bg*C3zfbQjVB0z*Fds=!R>E|f=GM;k(pFk literal 0 HcmV?d00001 diff --git a/chat/__pycache__/urls.cpython-36.pyc b/chat/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1db64cf8756d3a71a844a7c43ded03405fc462d GIT binary patch literal 304 zcmYL@zfQw25XR5WpO&T-&yl4b$^=yef`z3*f++)1RG$(;Y)7^Ol(mn*Q!wyCS(*9@ zOq_*8Pr6UPlkU6kR*S{V7hjJb0Ps!yUop`owL2q`AXx{Bm5hPpGU~XB%7_6n8DrGO zdrp)PC3{};GL`8)f!dExK`{~+sLw#+&e)KEZv8%eIMu8&jy3;&o@6l+*3ks$=+h%zXGw(K?x$LA{9+3 zC4z}Su_{Od@QL7xr(A?0`byGJbVLj`5`00%2X~N3#?<$Zoon7p+vwWLJ7|Q#@I)*U5%N+iCS{N?}MMlcrec@*&^SmAsqM~W*zMcBPsvm zcnA@oyC=%5{-`GfJb7Cd9zYAJY|Fjr!mSpv!TWn1u%Kz%#D|cuR`MnOh_*+c_G!%H F=r>Zpn^gb+ literal 0 HcmV?d00001 diff --git a/chat/admin.py b/chat/admin.py new file mode 100644 index 0000000..ce85145 --- /dev/null +++ b/chat/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from .models import * + +admin.site.register(Lobby) \ No newline at end of file diff --git a/chat/consumers.py b/chat/consumers.py new file mode 100644 index 0000000..11c286c --- /dev/null +++ b/chat/consumers.py @@ -0,0 +1,61 @@ +from asgiref.sync import async_to_sync +from channels.generic.websocket import WebsocketConsumer +import json +from .models import Lobby + +class ChatConsumer(WebsocketConsumer): + def connect(self): + self.room_name = self.scope['url_route']['kwargs']['room_name'] + self.room_group_name = f'chat_{self.room_name}' + + checkSave = False + for lobby in Lobby.objects.all(): + if lobby.name == self.room_name: + lobby.userCount = lobby.userCount + 1 + Lobby.save(lobby) + checkSave = True + break + if checkSave == False: + lobbyRegister = Lobby() + lobbyRegister.name= self.room_name + lobbyRegister.userCount = 1 + Lobby.save(lobbyRegister) + + async_to_sync(self.channel_layer.group_add)( + self.room_group_name, + self.channel_name + ) + + self.accept() + + def disconnect(self, close_code): + + updateCountOfUsers = Lobby.objects.get(name = self.room_name) + updateCountOfUsers.userCount = updateCountOfUsers.userCount - 1 + if updateCountOfUsers.userCount == 0: + Lobby.delete(updateCountOfUsers) + else: + Lobby.save(updateCountOfUsers) + + async_to_sync(self.channel_layer.group_discard)( + self.room_group_name, + self.channel_name + ) + + def receive(self, text_data): + text_data_json = json.loads(text_data) + message = text_data_json + + async_to_sync(self.channel_layer.group_send)( + self.room_group_name, + { + 'type': 'chat_message', + 'message': message + } + ) + + def chat_message(self, event): + message = event['message'] + + # Send message to WebSocket + self.send(text_data=json.dumps(message)) \ No newline at end of file diff --git a/chat/migrations/0001_initial.py b/chat/migrations/0001_initial.py new file mode 100644 index 0000000..aaa371d --- /dev/null +++ b/chat/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 2.2.6 on 2020-05-01 15:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Lobby', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('userCount', models.IntegerField()), + ], + ), + ] diff --git a/chat/migrations/__init__.py b/chat/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chat/migrations/__pycache__/0001_initial.cpython-36.pyc b/chat/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39938f424c93f97c4f842fe61a5ab194b063d67c GIT binary patch literal 674 zcmYjPJ#X7E5G5)3L$VxX=+qV+3uuX4bS(-84pIbYi~!A~Aq4F^%W@=9rKFSU*n_qv})_mF?#mFsqhr=xKQbrnIXYGRR^M zEEd3HCtQ4W-O1W?oTRXa3Ejwazipm`4}-zR9tux6zH!8(h{^bZZpgd08I8a;@siVFPl{szg2x~N1{i@12OutH0TL+;!3>&=ek&P@K*9*(mzRD2KczG$)edAwF%UBV03C!V5dZ)H literal 0 HcmV?d00001 diff --git a/chat/models.py b/chat/models.py new file mode 100644 index 0000000..5e0763b --- /dev/null +++ b/chat/models.py @@ -0,0 +1,25 @@ +from django.db import models +from django.http import HttpResponse +import json + +class Lobby(models.Model): + name = models.CharField(max_length=30) + userCount = models.IntegerField() + + def __str__(self): + return f"{self.id} {self.name} {self.userCount}" + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "name": self.name, + "userCount": self.userCount} + + def allObjectsDict(self): + objectAll = self.objects.all() + list = [] + for x in objectAll: + list.append(x.toDict()) + return json.dumps(list) \ No newline at end of file diff --git a/chat/routing.py b/chat/routing.py new file mode 100644 index 0000000..a1806ae --- /dev/null +++ b/chat/routing.py @@ -0,0 +1,7 @@ +from django.urls import re_path + +from . import consumers + +websocket_urlpatterns = [ + re_path(r'ws/(?P[^/]+)/$', consumers.ChatConsumer), +] \ No newline at end of file diff --git a/chat/urls.py b/chat/urls.py new file mode 100644 index 0000000..9b3230c --- /dev/null +++ b/chat/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path('', views.chatIndex), + path('', views.chatConnect) +] diff --git a/chat/views.py b/chat/views.py new file mode 100644 index 0000000..7a6550a --- /dev/null +++ b/chat/views.py @@ -0,0 +1,18 @@ +from django.http import HttpResponse +from .models import Lobby +import json + +# REST Definition + +def chatIndex(request): + if request.method == 'GET': + return HttpResponse(Lobby.allObjectsDict(Lobby)) + if request.method == 'POST': + Lobby.save(json.load(request)) + +def chatConnect(request, roomName): + if request.method == 'GET': + return HttpResponse(f'connect to {roomName}') + if request.method == 'DELETE': + return HttpResponse('leave the chatroom') + \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..a7768d39b778370fff38fa912f335fc1e6efda40 GIT binary patch literal 253952 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

d^LRXhhJj!KHwcwcrlX(B(=53oELFJ48cmQKEv( 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 RH$SB`C)EyQd@&F+002v}CJO)n literal 0 HcmV?d00001 diff --git a/generalApp/__pycache__/admin.cpython-36.pyc b/generalApp/__pycache__/admin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cea926cc5fa36ca50c7942426338f568b5c3813b GIT binary patch literal 433 zcmYk1zfQw25XS8^X+ud6;w{S146F$8Z>|sxO9v!3K2nF+u53r5Gf%_QuzO|d#>~XI zLc+HE>F4wLzPpREoPK}i&kIV(7l~Gae2vGxp>V=!Pb6JYN_fIYeNq#k-Ka|;d&k%x zk0YK$oJV{V@igM&h>O5HU6NV0M|U!#K4V-8wZ|^Qjh-)NCsb>FQ5&W#Yn;#u z6KW&cHvBFZ+KCs@U>ZJr5Oa!_2l=_JHd;cZL00$rbqED_)q~Loj|%H?xY=(1p#=qo d^&xf`ZNA<4{1TfVdbkQ>+B1|Q$&-S{`xl35b&vo6 literal 0 HcmV?d00001 diff --git a/generalApp/__pycache__/apps.cpython-36.pyc b/generalApp/__pycache__/apps.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6dd6da69a46ba3b72826e46b745e89ad7dbe42e2 GIT binary patch literal 376 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 literal 0 HcmV?d00001 diff --git a/generalApp/__pycache__/models.cpython-36.pyc b/generalApp/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..917c711698538b926157cd977ab0aecb0550160a GIT binary patch literal 14597 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 Yp0oHvD_dQzE>@qc9;`l5tyRD9zi~%CQUCw| literal 0 HcmV?d00001 diff --git a/generalApp/__pycache__/session.cpython-36.pyc b/generalApp/__pycache__/session.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd999a38185453915f713b38fb897330296739dc GIT binary patch literal 701 zcmY+A%}(1u5XWcNc47kNQ1t@h1$?PnA@vjxsFVv*gcPLGN3VrFeYx~uv0diVFA<0Ki~K0g2cq5+;@YjF){Z1#wq0i*uGFEH8!9F+-8 z#8I2U6w+ZXXJttY*uJsZF}sa2>Hs!y&;O65(tV|U74%i$tFW)aF~7(6MiZwC^b{h`%2A;R zHSKbi3z{s6((nXdIawcd3@06n?qhHQKcM~?LaP=d`mFdz1wWzIw{LVJq@xKrV?3dB z@fEJW6E(!xo>y?TP!oeCzD;bOKU#61w2FD}G4nuC!ktMP`0058zOyCU-|Dr;Nf~1tlKFgI9TyhO7Vp literal 0 HcmV?d00001 diff --git a/generalApp/__pycache__/urls.cpython-36.pyc b/generalApp/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a05a39b4e73e6c8a045e1faad34e9a80eed00e68 GIT binary patch literal 1169 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 int(candle['Min']) and triggerDate < candleDate: + inArea += 1 + if int(trigger['course_values_for_trigger']) < int(candle['Max']) and triggerDate < candleDate: + inArea += 1 + if inArea == 2: + disableTrigger = Triggers.objects.get(id = int(trigger['id'])) + disableTrigger.status = 0 + message = f"Exchange got Your Trigger Value! \nTrigger Value: {trigger['course_values_for_trigger']} \nCandle Date: {candle['Date']}" + newNotification = Notifications(user_id = int(trigger['user_id']), message = message) + newNotification.save() + disableTrigger.save() + inArea = 0 + print(self.triggerList) + + @classmethod + def createActualPrognosis(self, request, time, price, privilige): + actualGraph = self.refreshGraph(time) + svg = [] + svgAll = 0 + volume = [] + actualCourse = 0 + for candle in actualGraph['candles']: + svg.append((float(candle['Close'] + candle['Open']) / 2)) + volume.append(float(candle['Volume'])) + actualCourse = float(candle['Close']) + datePayment = candle['Date'] + if svgAll == 0: + svgAll = svgAll + svg[-1] + else: + svgAll = (svgAll + svg[-1]) / 2 + onePercentOfActualCourse = actualCourse / 100 + percentsFromPriceToCourse = price / onePercentOfActualCourse + onePercentOfSvgCourse = svgAll / 100 + priceAfterCourse = percentsFromPriceToCourse * onePercentOfSvgCourse + difference = priceAfterCourse - price + percentDifference = difference / onePercentOfSvgCourse + data = { + "price" : price, + "price_forecast" : priceAfterCourse, + "percent_of_difference" : percentDifference, + "course_on_payment" : actualCourse, + "svg_of_all" : svgAll, + "date_of_transaction" : datePayment + } + return HttpResponse(json.dumps(data)) + + @classmethod + def refreshGraph(self, time): + graph = [] + try: + graph = self.createGraph(time) + except: + currentDirectory = os.path.dirname(__file__) + jsonPath = os.path.join(currentDirectory, '../testGraph.txt') + with open(jsonPath) as graphJson: + graph = json.load(graphJson) + return self.createGraph(time) + + @classmethod + def createGraph(self, time): + miliseconds = 1000 + firstResult = int(datetime.now().timestamp() * miliseconds) + lastResult = firstResult - 100000 * (time * 2) + url = f"https://api.bitbay.net/rest/trading/candle/history/BTC-PLN/{time}?from={lastResult}&to={firstResult}" + querystring = {"from": f"{lastResult}","to": f"{firstResult}"} + exchangeGraph = requests.request("GET", url, params=querystring) + response = json.loads(exchangeGraph.text) + graph = { 'candles': [], 'candlesCount' : 0, 'graphMin': float(response['items'][0][1]['h']), 'graphMax': 0 } + for x in range(len(response['items'])): + graph['candles'].append({'Open': 0, 'Close': 0, 'Max': 0, 'Min': 0, 'Volume': 0, 'Date': 0 }) + graph['candles'][x]['Open'] = float(response['items'][x][1]['o']) + graph['candles'][x]['Close'] = float(response['items'][x][1]['c']) + graph['candles'][x]['Max'] = float(response['items'][x][1]['h']) + graph['candles'][x]['Min'] = float(response['items'][x][1]['l']) + graph['candles'][x]['Volume'] = float(response['items'][x][1]['v']) + graph['candles'][x]['Date'] = str(datetime.fromtimestamp(int(response['items'][x][0])/1000.0)) + if graph['candles'][x]['Min'] < graph['graphMin']: + graph['graphMin'] = graph['candles'][x]['Min'] + if graph['candles'][x]['Max'] > graph['graphMax']: + graph['graphMax'] = graph['candles'][x]['Max'] + graph['candlesCount'] = len(response['items']) - 1 + return graph + + @classmethod + def getGraphView(self, request, time): + graph = [] + try: + graph = self.createGraph(time) + except: + currentDirectory = os.path.dirname(__file__) + jsonPath = os.path.join(currentDirectory, '../testGraph.txt') + with open(jsonPath) as graphJson: + graph = json.load(graphJson) + return HttpResponse(json.dumps(graph)) diff --git a/generalApp/methods.py b/generalApp/methods.py new file mode 100644 index 0000000..ac70cda --- /dev/null +++ b/generalApp/methods.py @@ -0,0 +1,166 @@ +from django.http import HttpResponse +from django.db import connection +from .exchangeVO import * +from .utilities import * +from .models import * +import requests +import json +import time + +# Exchange Asynchronic Notifications + +@newThread +def checkTriggerNotification(): + while True: + ExchangeVO.checkTrigger() + connection.close() + time.sleep(1800) + +# Exchange POST Methods + +def addTrigger(request, userID): + return Triggers.addObject(request, userID, 1) + +def addTransaction(request, userID): + return Transactions.addObject(request, userID, 1) + +def Prognosis(request, time, price): + return ExchangeVO.createActualPrognosis(request, time, price, 1) + +# Exchange GET Methods + +def getExchangeGraph(request, time): + return ExchangeVO.getGraphView(request, time) + +def getTrigger(request, id): + return Triggers.getObject(request, id, 1) + +def getTransaction(request, id): + return Transactions.getObject(request, id, 1) + +def getUserTriggers(request, userID): + return Triggers.getObjectsByParentID(request, userID, 1) + +def getUserTransactions(request, userID): + return Transactions.getObjectByParentID(request, userID, 1) + +def getTriggersAll(request): + return Triggers.getAllObjects(request, 2) + +def getTransactionsAll(request): + return Transactions.getAllObjects(request, 2) + +def getUserNotifications(request, userID): + return Notifications.getObjectsByParentID(request, userID, 1) + +# Exchange PUT Methods + +def putTrigger(request, id): + return Triggers.putObject(request, id, 1) + +def putTransaction(request, id): + return Transactions.putObject(request, id, 1) + +# Exchange DELETE Methods + +def deleteTrigger(request, id): + return Triggers.deleteObject(request, id, 1) + +def deleteTransaction(request, id): + return Transactions.deleteObject(request, id, 1) + +def deleteNotification(request, id): + return Notifications.deleteObject(request, id, 1) + +# Forum POST Methods + +def loginUser(request): + login = jsonLoad(request) + if login['login'] is not None and login['password'] is not None: + users = Users.objects.all() + for x in users: + if x.login == login['login']: + if checkPassHash(login['password'], x.password): + newSession = createSession(request, x.toDict()) + return HttpResponse(json.dumps({ 'token': newSession })) + return HttpResponse("Login Failed") + +def logoutUser(request): + return deleteSession(request) + +def registerUser(request): + return Users.addObject(request, None, None) + +def addThread(request): + return Threads.addObject(request, None, 2) + +def addSubject(request, threadID): + return Subjects.addObject(request, threadID, 1) + +def addComment(request, subjectID): + return Comments.addObject(request, subjectID, 1) + +def addRating(request, commentID): + return Ratings.addObject(request, commentID, 1) + +# Forum GET Methods + +def getUser(request, id): + return Users.getObject(request, id, 2) + +def getUsersAll(request): + return Users.getAllObjects(request, 2) + +def getThreadsAll(request): + return Threads.getAllObjects(request, 1) + +def getThreadSubjects(request, threadID): + return Subjects.getObjectsByParentID(request, threadID, 1) + +def getSubjectComments(request, subjectID): + return Comments.getObjectsByParentID(request, subjectID, 1) + +def getCommentRatings(request, commentID): + return Ratings.getObjectsByParentID(request, commentID, 1) + +# Forum PUT Methods + +def putUser(request, id): + return Users.putObject(request, id, 1) + + +def putThread(request, id): + return Threads.putObject(request, id, 2) + + +def putSubject(request, id): + return Subjects.putObject(request, id, 1) + + +def putComment(request, id): + return Comments.putObject(request, id, 1) + + +def putRating(request, id): + return Ratings.putObject(request, id, 1) + +# Forum DELETE Methods + +def deleteUser(request, id): + return Users.deleteObject(request, id, 1) + + +def deleteThread(request, id): + return Threads.deleteObject(request, id, 2) + + +def deleteSubject(request, id): + return Subjects.deleteObject(request, id, 1) + + +def deleteComment(request, id): + return Comments.deleteObject(request, id, 1) + + +def deleteRating(request, id): + return Ratings.deleteObject(request, id, 1) diff --git a/generalApp/migrations/0001_initial.py b/generalApp/migrations/0001_initial.py new file mode 100644 index 0000000..ac3d48d --- /dev/null +++ b/generalApp/migrations/0001_initial.py @@ -0,0 +1,110 @@ +# Generated by Django 2.2.6 on 2019-12-19 16:17 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Comments', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=255)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Users', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('login', models.CharField(max_length=30)), + ('password', models.CharField(max_length=30)), + ('email', models.EmailField(max_length=50)), + ('privilige', models.IntegerField(default=1)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Triggers', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('course_values_for_trigger', models.FloatField(default=255)), + ('date_of_trigger', models.DateTimeField(verbose_name='date of trigger')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Transactions', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('price', models.FloatField(default=255)), + ('price_forecast', models.FloatField(default=255)), + ('currency', models.CharField(max_length=255)), + ('date_of_transaction', models.DateTimeField(verbose_name='date of transaction')), + ('course_on_payment', models.FloatField(default=255)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Threads', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Subjects', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30)), + ('thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Threads')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Ratings', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.IntegerField()), + ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Comments')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='comments', + name='subject', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Subjects'), + ), + migrations.AddField( + model_name='comments', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users'), + ), + ] diff --git a/generalApp/migrations/0002_triggers_status.py b/generalApp/migrations/0002_triggers_status.py new file mode 100644 index 0000000..46182af --- /dev/null +++ b/generalApp/migrations/0002_triggers_status.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-12-29 13:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='triggers', + name='status', + field=models.IntegerField(default=1), + ), + ] diff --git a/generalApp/migrations/0003_auto_20191229_1407.py b/generalApp/migrations/0003_auto_20191229_1407.py new file mode 100644 index 0000000..6410703 --- /dev/null +++ b/generalApp/migrations/0003_auto_20191229_1407.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2019-12-29 14:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0002_triggers_status'), + ] + + operations = [ + migrations.AlterField( + model_name='triggers', + name='date_of_trigger', + field=models.CharField(max_length=255), + ), + ] diff --git a/generalApp/migrations/0004_notifications.py b/generalApp/migrations/0004_notifications.py new file mode 100644 index 0000000..ad78019 --- /dev/null +++ b/generalApp/migrations/0004_notifications.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2.6 on 2019-12-29 15:59 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0003_auto_20191229_1407'), + ] + + operations = [ + migrations.CreateModel( + name='Notifications', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('message', models.CharField(max_length=255)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='generalApp.Users')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/generalApp/migrations/0005_users_avatar.py b/generalApp/migrations/0005_users_avatar.py new file mode 100644 index 0000000..37e513c --- /dev/null +++ b/generalApp/migrations/0005_users_avatar.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2020-01-03 16:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0004_notifications'), + ] + + operations = [ + migrations.AddField( + model_name='users', + name='avatar', + field=models.CharField(default='none', max_length=255), + ), + ] diff --git a/generalApp/migrations/0006_auto_20200113_2147.py b/generalApp/migrations/0006_auto_20200113_2147.py new file mode 100644 index 0000000..4932d2d --- /dev/null +++ b/generalApp/migrations/0006_auto_20200113_2147.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2020-01-13 21:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0005_users_avatar'), + ] + + operations = [ + migrations.AlterField( + model_name='comments', + name='text', + field=models.CharField(max_length=1000), + ), + ] diff --git a/generalApp/migrations/0007_auto_20200115_1743.py b/generalApp/migrations/0007_auto_20200115_1743.py new file mode 100644 index 0000000..b26e51c --- /dev/null +++ b/generalApp/migrations/0007_auto_20200115_1743.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2020-01-15 17:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('generalApp', '0006_auto_20200113_2147'), + ] + + operations = [ + migrations.AlterField( + model_name='users', + name='password', + field=models.CharField(max_length=200), + ), + ] diff --git a/generalApp/migrations/__init__.py b/generalApp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/generalApp/migrations/__pycache__/0001_initial.cpython-36.pyc b/generalApp/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c336b66e94ce8ce677fa1a5d849e2544625f096 GIT binary patch literal 2039 zcmb7FNpIUm6efqHNNu*fq_xvFb@!@^Qw*ABa3+&$vu$kF+ZmqTho&H4(gBfiTj5YzYZ3RZ#W=_8V1T5zEJuvaI!GXe^-6Pb+d@*LP+(Q2rbU}x&vMXd~bu&>dbHS~KM(ci+H3Ra|Z z;BC~ZZ~%u20q&!=#kTvkzT4mF@4`Fq?j6Cp?KR~0HX=V*L4JQlJ3?*V2lxQBDttIy z^`n)@SJmLI)$sAg8a~nM%zF1KENczx)7QZI43U?6^LgHz*X~(;;~HNeYWdc{-ha7< z|J57e@4?s5SVL$k1US~Sru-Ybq5MIyy$=s@KRlAf=d+E_lHMtgW0qv8Bq3Z#^7O23 z%L*N4-0uoTGX}Ce5MfNk$bZR3vY0Xv(kL7=S-EDS!&BxbG-lGy*iAP154TU<#H~he z{D>t%b|pR9Ni#vaS>2Mh4lVRT7C|aqKFD{Y^An<`(usHwCX)w9ClF z(d3b`7O|A;FbV@UG4qvNU_CmFGU>HM7z7IDu*-)6%etn~kfnZ)3qQ+!avSiCeBPTG z#@cYidq>lVx+%(PA$y1wjcWl*n4rFNs4c$j}-^& z>oU2e|J2H?OH-_^I~0N?-I3f|6fjR4Yhzx-+$eXZZ-L7V=txl{-PRRS0;y03mGmx$ zoj&U#bA?RX$Gc1APD7>pBc6CkfX&tIkZw2Ud%U+4Jf8t?>P2qS9DOBjwjwfF(g&!f zJ}<}7q`s)%lb)~5zAsC@k72`zpFsqmlkJ!YvZIh6F zvu2g7T-q|#wW{A=^Qwqt+p>JHe*Rn!ZznD?jw9ZgQo$Kl-A$iJhF gS@*>EsyXTn7H!I<3$#h^+k76rQ?#ZktY&)F|I$E0H2?qr literal 0 HcmV?d00001 diff --git a/generalApp/migrations/__pycache__/0002_triggers_status.cpython-36.pyc b/generalApp/migrations/__pycache__/0002_triggers_status.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2d0e5f263725606defc40f1c893cfa4f6cfbeac GIT binary patch literal 591 zcmYjO&1&2*5SA?4>optbrG12gp~Tzv8bSi4rH6z-dora$-I=&{Y}t|I!=BS?9wNt_ z@;V&_kEu}9v$TmPub5cXY4QgZ^h)F(XnsI00Z8!o>#n&s)(~M z3?dMJ7zpI8xD%Ct_!}#dXUb(oib?4*gSL^lqy=-*j8rAvCnWnDM z(0J>Vo9r|3V+HpMz-u*it`Gz=0Fzqv=;PTY*9~@XSwtqGY!grxOP|R(M@pYdNi|c4 zom3a*}j^NQmYqpARDep9Okk=5?4B%*&7R z_t0ZGU|)V3Zl)f!+m=^mXmR6g`Q0c$B71NS0+a{IOOoP)+$$h=0vwN96aF-ivN@Sd tq;bq6+VlHm5&I>yO4q|N{F*7uz~|rr;m&(Q^*%e{}>^J-GgruL-Gml9C1KzQoSG*6ZfU`FY z0ubLB2;{B!CMp5pdzMGHl*{tKWqng?Wt(v@F78Lb&TM>We_~S3>6s@akX0O56+l|^ zN?_PVKc z?{IfPS(M||KIQf=jm|kiRbOR?Lv6RYAj^Z5gX+tMT*P<6y6gcY17bV@>fvD?s9ZP!2mO4!=;)c21?5?I_pf>TI=M zpUKtJ^4ZCBt^H4XS|%frh&T*+KzH$9=AlcWRYN_Vz^8@80(=P`K<>1MRPU1KyLG(q K{ETOPPy7S%My198 literal 0 HcmV?d00001 diff --git a/generalApp/migrations/__pycache__/0004_notifications.cpython-36.pyc b/generalApp/migrations/__pycache__/0004_notifications.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b48424d69de4a9f59f16b63bba939c0e8537d6a GIT binary patch literal 876 zcmYjPOK;Oa5VqHjV>^$QhlJq71*BZ^Xe*&g2sKJ6LZ}r|%f$zlO=jZSwY_22L8Mo> z=7;cO_yc?8)W5(5#ttQ2Ye)0&&dm4C>~}ihr=R}E8)jL*tUJdg{fMsalK>0s%*yS^ z&RN9l%4V4pxo<3R!2NE4i+0-h=0pu(=T@(ALvO4eGhv>@N|cE#wDEEYnCY`w6}vqF zDMxhmlmuFl4OYb9er!h$x@n`zj$Yb?27Mkh!C$*`1_Ake2%)vM$!e1oV3@X2FKwqC z=samKntIF&cpV#F%HzDUVh-HSPw>kg36j_y_vH%xY z02Z?ZwW58nOlwkuJFO!xY^ zra2j(PsYcuO(++{dEMj>OFgT4til}vF~>cNE)fHbGA zvSn$oU9tg9@qib1C)QuARJF@Zy1GlkcRbg%8GC4V?I%th>v<;Fblrz(jeG<4@qcH3 iv%LLVJnAWBs^4xQY_#VTF#gL8$FC~RbX9)W_MN{Gb^z-D literal 0 HcmV?d00001 diff --git a/generalApp/migrations/__pycache__/0005_users_avatar.cpython-36.pyc b/generalApp/migrations/__pycache__/0005_users_avatar.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9fbbbde36263753e5649574230800260e2b005f GIT binary patch literal 608 zcmYjOv5wR*5VhkZn*@|Z3 z#CHY)c_+S!T0s1cmB}^LvNH0;&^A_0tg8}T_Hl%LOikwrrZcPSR&4JYs6b-Kh z#$5u`4%2Q038b*PiXgiZl*=HeA-8<~=BB$Z8q{c2e>RT({${gzBDI;?UAz4^JeeI@ z;-D_nq^ys%(Rlrbh7!pY;7-l`L~PYp*`sczeJLmke5FkUiwWh=EfjN5VhkZO(H6RL~optBB3U`<>P`-D-fKhkl>U9mf0Dy3Hhq+p!Qh7wLgTv z6nKEz<_tG=N0dRD&Xu5 zg8;;L1_F62zKKde_@3p_A9~C3z-4_?Yh{~pFfQ&#z|L%Z=yt_qoYFCm2#{4ASQS88 z^GaaYMnL5-ZVw=W_=dy5ji5*Z3AM;v`u4WA%W51@tL|)?+`Y0apUByuHd1|6R%w@P z#=ghF8W&o;w9RipkV<%5}Le%hl>c zu2+wr9Zy%<|E-s0GJ-_JVaNm8%l&yCx)fS9)Z;OHT0|_wm*Ae{&N`xemptE%i_@% literal 0 HcmV?d00001 diff --git a/generalApp/migrations/__pycache__/0007_auto_20200115_1743.cpython-36.pyc b/generalApp/migrations/__pycache__/0007_auto_20200115_1743.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e642e154f2666980afe280f06659386f5a16b06 GIT binary patch literal 606 zcmY*W&2H2%5VqrFn?zLN0zGm=iiDc%ZecGKYQ^7)f&`}=u*}Yo-H^n=PDFbKiBlhh zH{lt4<RkxeMkTdc*9y=@-`>~ z&R#JHKzwH)kk{gyC8Z8>@;$B(%RU5eZMLjc4GpbA3U{?*BOpxcNl$~nPg%d`fw%EW$7MO?< zj2}5mTr8(IQo2-1${8CZ`;L@fM%DN{?*aDM0e0&xS`$#BOV67D%}Za=2!D}0+o+xI zQr#1YNvxmD-1E&m{E_)ax0q{e^XK~W*kU(aSTG`Um5?!o|a7sVlfLt9?+idFS5`jP^+%e$MA6?F%3Qi_e1Wi`;_nE)14eo LJwNMN-xYrWe2|~k literal 0 HcmV?d00001 diff --git a/generalApp/migrations/__pycache__/__init__.cpython-36.pyc b/generalApp/migrations/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6d565b0d91a65c1856f13f03abaab92bc18ccd8 GIT binary patch literal 163 zcmXr!<>i{$@;jCR2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUjh0V`MIh3`Kh`3 zF8SG|xv6<2mHGii`B|ySCB^z7MTse?js*n>MtW*qYEfbiNGvxqy(qCHGe56bKR!M) cFS8^*Uaz3?7Kcr4eoARhsvXFtVjyM!0L*wRc>n+a literal 0 HcmV?d00001 diff --git a/generalApp/models.py b/generalApp/models.py new file mode 100644 index 0000000..5543417 --- /dev/null +++ b/generalApp/models.py @@ -0,0 +1,350 @@ +from django.db import models +from django.http import HttpResponse +from django.db.models import Avg +from datetime import datetime +from .utilities import * + +class ObjectAbstract(models.Model): + + @classmethod + def addObject(self, request, parentID, privilige): + if self.modelIsUser(self) or checkSession(request, privilige): + object = jsonLoad(request) + if self.modelIsUser(self): + object['privilige'] = 1 + object['password'] = createPassHash(object['password']) + if self.checkUniqueValues(self, parentID, object): + return self.saveObject(self, parentID, object) + else: + return HttpResponse("Object Is Already Exist") + else: + return HttpResponse("No Permission") + + def modelIsUser(model): + return model == Users + + def checkUniqueValues(model, parentID, objectDict): + objectsAll = model.allObjectsDict(model) + for x in objectsAll: + if model == Users: + if x['login'].upper() == objectDict['login'].upper(): + return False + elif model == Threads: + if x['name'].upper() == objectDict['name'].upper(): + return False + elif model == Ratings: + if int(x['user_id']) == int(objectDict['user_id']) and int(x['comment_id']) == parentID: + return False + return True + + def allObjectsDict(model): + objectAll = model.objects.all() + list = [] + for x in objectAll: + list.append(x.toDict()) + return list + + def modelIsNotUser(model): + return model != Users + + def saveObject(model, parentID, objectDict): + newObject = model() + newObject.fromDict(objectDict) + if model.modelHaveParent(model): + newObject.setParentID(parentID) + if model.modelIsTrigger(model): + newObject.setActualTime() + newObject.save() + if model.modelIsSubject(model) and model.newCommentInNewSubject(objectDict): + newComment = Comments(subject = newObject) + newComment.fromDict(objectDict['comment']) + newComment.save() + return HttpResponse(f"{model.__name__}/{Comments}: Add new Objects: {newObject.toDict()} and {newComment.toDict()}") + return HttpResponse(f"{model.__name__}: Add new Object: {newObject.toDict()}") + + def modelHaveParent(model): + return model != Threads and model != Users + + def modelIsTrigger(model): + return model == Triggers + + def modelIsSubject(model): + return model == Subjects + + def newCommentInNewSubject(objectDict): + return 'comment' in objectDict + + @classmethod + def getObject(self, request, objectID, privilige): + return self.getObjectNormal(self, objectID) + + def getObjectNormal(model, objectID): + object = model.objects.get(pk = objectID).toDict() + return HttpResponse(json.dumps(object)) + + @classmethod + def getAllObjects(self, request, privilige): + objectsAll = self.allObjectsDict(self) + return HttpResponse(json.dumps(objectsAll)) + + @classmethod + def getObjectsByParentID(self, request, parentID, privilige): + if self.modelHaveParent(self): + return HttpResponse(self.getAllByParentID(parentID)) + return HttpResponse("No Permission") + + @classmethod + def putObject(self, request, objectID, privilige): + if checkSession(request, privilige): + object = jsonLoad(request) + return self.updateObject(self, request, object, objectID) + else: + return HttpResponse("No Permission") + + def updateObject(model, request, objectDict, objectID): + objectOld = model.objects.get(pk = objectID) + if model.modelIsUser(model): + if checkPassHash(objectDict['passwordOld'], objectOld.password): + if 'passwordNew' in objectDict.keys(): + objectDict['password'] = createPassHash(objectDict['passwordNew']) + else: + return HttpResponse('Bad Password') + objectOld.fromDict(objectDict) + if checkUserPermission(objectOld.toDict(), request): + objectOld.save() + return HttpResponse(f"{model.__name__}: {objectOld.toDict()} has been updated") + else: + return HttpResponse("No Permission") + + @classmethod + def deleteObject(self, request, objectID, privilige): + if checkSession(request, privilige): + objectDel = self.objects.get(pk = objectID) + if checkUserPermission(objectDel.toDict(), request): + if self.modelIsUser(self): + if checkPassHash(objectDict['password'], objectDel.password): + pass + else: + return HttpResponse("Bad Password") + objectDel.delete() + return HttpResponse(f"{self.__name__}: {objectDel} has been deleted") + else: + return HttpResponse("No Permission") + else: + return HttpResponse("No Permission") + + class Meta: + abstract = True + +class Users(ObjectAbstract): + login = models.CharField(max_length=30) + password = models.CharField(max_length=200) + email = models.EmailField(max_length=50) + avatar = models.CharField(max_length=255, default='none') + privilige = models.IntegerField(default=1) + + def __str__(self): + return f"{self.id} {self.login}" + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "login": self.login, + "avatar": self.avatar, + "email": self.email, + "privilige": self.privilige} + +class Threads(ObjectAbstract): + name = models.CharField(max_length=30) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + + def __str__(self): + return self.name + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "name": self.name, + "user_id": self.user.id, + "moderator": self.user.login, + "moderator_avatar": self.user.avatar, + "moderator_privilige": self.user.privilige} + +class Subjects(ObjectAbstract): + name = models.CharField(max_length=30) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + thread = models.ForeignKey(Threads, on_delete = models.CASCADE) + + def __str__(self): + return f"{self.id} {self.name}" + + def setParentID(self, parentID): + self.__dict__.update({ "thread_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + list = [ x.toDict() for x in self.objects.filter(thread_id = parentID)] + return json.dumps(list) + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "name": self.name, + "user_id": self.user.id, + "author": self.user.login, + "author_avatar": self.user.avatar, + "author_privilige": self.user.privilige, + "thread_id": self.thread.id, + "thread_name": self.thread.name} + +class Comments(ObjectAbstract): + text = models.CharField(max_length=1000) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + subject = models.ForeignKey(Subjects, on_delete = models.CASCADE) + + def __str__(self): + return f"{self.user} -> {self.subject}" + + def setParentID(self, parentID): + self.__dict__.update({ "subject_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + list = [ x.toDict() for x in self.objects.filter(subject_id = parentID)] + return json.dumps(list) + + def commentSVG(self): + return + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "text": self.text, + "ratings_avg": Ratings.objects.filter(comment_id = self.id).aggregate(Avg('value')), + "user_id": self.user.id, + "author": self.user.login, + "author_avatar": self.user.avatar, + "author_privilige": self.user.privilige, + "subject_id": self.subject.id, + "subject_name": self.subject.name} + +class Ratings(ObjectAbstract): + value = models.IntegerField() + user = models.ForeignKey(Users, on_delete = models.CASCADE) + comment = models.ForeignKey(Comments, on_delete = models.CASCADE) + + def __str__(self): + return f"{self.user}, value: {self.value} -> comment in: {self.comment.subject}" + + def setParentID(self, parentID): + self.__dict__.update({ "comment_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + list = [ x.toDict() for x in self.objects.filter(comment_id = parentID)] + return json.dumps(list) + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "value": self.value, + "user_id": self.user.id, + "author": self.user.login, + "author_avatar": self.user.avatar, + "comment_id": self.comment.id, + "subject": self.comment.subject.name} + +class Transactions(ObjectAbstract): + price = models.FloatField(default=255) + price_forecast = models.FloatField(default=255) + currency = models.CharField(max_length=255) + date_of_transaction = models.DateTimeField('date of transaction') + course_on_payment = models.FloatField(default=255) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + + def __str__(self): + return f"{self.user.login}, cash: {self.price}, prognosis: {self.price_forecast}" + + def setParentID(self, parentID): + self.__dict__.update({ "user_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + list = [ x.toDict() for x in self.objects.filter(user_id = parentID)] + return json.dumps(list) + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "price": self.price, + "currency": self.currency, + "date_of_transaction": self.date_of_transaction, + "course_on_payment": self.course_on_payment, + "user_id": self.user.id, + "author": self.user.login, + "exchange_id": self.exchange.id} + +class Triggers(ObjectAbstract): + course_values_for_trigger = models.FloatField(default=255) + date_of_trigger = models.CharField(max_length=255) + status = models.IntegerField(default=1) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + + def __str__(self): + return f"{self.user.login}, trigger value: {self.course_values_for_trigger}, date: {self.date_of_trigger}" + + def setParentID(self, parentID): + self.__dict__.update({ "user_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + list = [ x.toDict() for x in self.objects.filter(user_id = parentID)] + return json.dumps(list) + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "course_values_for_trigger": self.course_values_for_trigger, + "date_of_trigger": self.date_of_trigger, + "status": self.status, + "user_id": self.user.id, + "author": self.user.login,} + + def setActualTime(self): + self.date_of_trigger = str(datetime.now().strftime("%Y-%d-%m %H:%M")) + +class Notifications(ObjectAbstract): + message = models.CharField(max_length=255) + user = models.ForeignKey(Users, on_delete = models.CASCADE) + + def __str__(self): + return f"Message: {self.message}, for User: {self.user.login}" + + def setParentID(self, parentID): + self.__dict__.update({ "user_id": parentID }) + + @classmethod + def getAllByParentID(self, parentID): + return json.dumps(list(self.objects.filter(user_id = parentID).values())) + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self): + return {"id": self.id, + "message": self.message, + "user_id": self.user.id} diff --git a/generalApp/tests.py b/generalApp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/generalApp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/generalApp/urls.py b/generalApp/urls.py new file mode 100644 index 0000000..431ecb9 --- /dev/null +++ b/generalApp/urls.py @@ -0,0 +1,30 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path('authUser', views.authUser), + path('user', views.users), + path('user/', views.user), + + path('thread', views.threads), + path('thread/', views.thread), + path('thread//subject', views.subjects), + path('subject/', views.subject), + path('subject//comment', views.comments), + path('comment/', views.comment), + path('comment//rating', views.ratings), + path('rating/', views.rating), + + path('exchange/', views.exchangeGraph), + path('exchange//prognosis/', views.exchangePrognosis), + path('user//transaction', views.transactions), + path('transaction/', views.transaction), + path('transaction/all', views.transactionsAll), + path('user//trigger', views.triggers), + path('trigger/', views.trigger), + path('trigger/all', views.triggersAll), + path('user//notification', views.notifications), + path('notification/', views.notification) + +] diff --git a/generalApp/utilities.py b/generalApp/utilities.py new file mode 100644 index 0000000..27612dd --- /dev/null +++ b/generalApp/utilities.py @@ -0,0 +1,121 @@ +from hmac import compare_digest as checkHash +from django.http import HttpResponse +from threading import Thread +import threading +import requests +import crypt +import json +import jwt + +# Session / Token Methods + +tokenKey = 'U0VDUkVUX1BBU1NfQ0hFQ0s#!@#SDS!#' +tokens = [] + +def createSession(request, userDict): + newToken = createToken(userDict) + tokens.append(newToken) + return newToken + +def createToken(userDict): + return jwt.encode( { 'payload': userDict }, tokenKey, algorithm = 'HS256' ).decode('UTF-8') + +def checkSession(request, privilige): + token = tryGetTokenFromRequest(request) + for currentToken in tokens: + if token == currentToken: + if decodeToken(currentToken)['payload']['privilige'] >= privilige: + return True + else: + return False + return False + +def tryGetTokenFromRequest(request): + try: + return jsonLoad(request)['token'] + except: + pass + +def decodeToken(token): + return jwt.decode( token, tokenKey, algorithms = ['HS256'] ) + +def checkUserPermission(modelDict, request): + + def UserIsAdmin(token): + return decodeToken(token)['payload']['privilige'] == 3 + + def UserIsModer(token): + return decodeToken(token)['payload']['privilige'] == 2 + + def checkUserChanges(modelDict, token): + return decodeToken(token)['payload']['id'] == modelDict['user_id'] + + def checkUser(modelDict, token): + return decodeToken(token)['payload']['id'] == modelDict['id'] + + def modelIsNotUser(modelDict): + return 'user_id' in modelDict + + def modelIsUser(modelDict): + return 'login' in modelDict + + def checkCheats(modelDict, token): + if 'privilige' in modelDict: + if modelDict['privilige'] != decodeToken(token)['payload']['privilige']: + return True + else: + return False + else: + return False + + token = tryGetTokenFromRequest(request) + if modelIsNotUser(modelDict): + if UserIsAdmin(token): + return True + elif UserIsModer(token): + return True + elif checkUserChanges(modelDict, token): + return True + else: + return False + elif modelIsUser(modelDict): + if UserIsAdmin(token): + return True + elif checkCheats(modelDict, token): + return False + elif checkUser(modelDict, token): + return True + else: + return False + +def deleteSession(request): + token = jsonLoad(request)['token'] + try: + tokens.remove(token) + return HttpResponse("Session Has Been Deleted") + except: + return HttpResponse("Session Delete Error") + +# Security Hash / Crypt Methods + +def createPassHash(password): + return crypt.crypt(password) + +def checkPassHash(password, hashedPass): + return checkHash(hashedPass, crypt.crypt(password, hashedPass)) + +# Thread Method + +def newThread(function): + + def decorator(*args, **kwargs): + thread = Thread(target = function, args = args, kwargs = kwargs) + thread.daemon = True + thread.start() + + return decorator + +# JSON Load Method + +def jsonLoad(self): + return json.loads(self.body.decode('utf-8')) diff --git a/generalApp/views.py b/generalApp/views.py new file mode 100644 index 0000000..539fc98 --- /dev/null +++ b/generalApp/views.py @@ -0,0 +1,179 @@ +from django.http import HttpResponse +from .methods import * + +# Threads Start + +checkTriggerNotification() + +# REST Definition + +def authUser(request): + if request.method == 'POST': + return loginUser(request) + elif request.method == 'DELETE': + return logoutUser(request) + else: + return HttpResponse('Bad Request Method') + + +def users(request): + if request.method == 'GET': + return getUsersAll(request) + elif request.method == 'POST': + return registerUser(request) + else: + return HttpResponse('Bad Request Method') + + +def user(request, id): + if request.method == 'GET': + return getUser(request, id) + elif request.method == 'PUT': + return putUser(request, id) + elif request.method == 'DELETE': + return deleteUser(request, id) + else: + return HttpResponse('Bad Request Method') + + +def threads(request): + if request.method == 'GET': + return getThreadsAll(request) + elif request.method == 'POST': + return addThread(request) + else: + return HttpResponse('Bad Request Method') + + +def thread(request, id): + if request.method == 'PUT': + return putThread(request, id) + elif request.method == 'DELETE': + return deleteThread(request, id) + else: + return HttpResponse('Bad Request Method') + + +def subjects(request, threadID): + if request.method == 'GET': + return getThreadSubjects(request, threadID) + elif request.method == 'POST': + return addSubject(request, threadID) + else: + return HttpResponse('Bad Request Method') + + +def subject(request, id): + if request.method == 'PUT': + return putSubject(request, id) + elif request.method == 'DELETE': + return deleteSubject(request, id) + else: + return HttpResponse('Bad Request Method') + + +def comments(request, subjectID): + if request.method == 'GET': + return getSubjectComments(request, subjectID) + elif request.method == 'POST': + return addComment(request, subjectID) + else: + return HttpResponse('Bad Request Method') + + +def comment(request, id): + if request.method == 'PUT': + return putComment(request, id) + elif request.method == 'DELETE': + return deleteComment(request, id) + else: + return HttpResponse('Bad Request Method') + + +def ratings(request, commentID): + if request.method == 'GET': + return getCommentRatings(request, commentID) + elif request.method == 'POST': + return addRating(request, commentID) + else: + return HttpResponse('Bad Request Method') + +def rating(request, id): + if request.method == 'PUT': + return putRating(request, id) + elif request.method == 'DELETE': + return deleteRating(request, id) + else: + return HttpResponse('Bad Request Method') + +def exchangeGraph(request, time): + if request.method == 'GET': + return getExchangeGraph(request, time) + else: + return HttpResponse('Bad Request Method') + +def exchangePrognosis(request, price, time): + if request.method == 'GET': + return Prognosis(request, time, price) + else: + return HttpResponse('Bad Request Method') + +def transactions(request, userID): + if request.method == 'GET': + return getUserTransactions(request, userID) + elif request.method == 'POST': + return addTransaction(request, userID) + else: + return HttpResponse('Bad Request Method') + +def transaction(request, id): + if request.method == 'GET': + return getTransaction(request, id) + elif request.method == 'PUT': + return putTransaction(request, id) + elif request.method == 'DELETE': + return deleteTransaction(request, id) + else: + return HttpResponse('Bad Request Method') + +def transactionsAll(request): + if request.method == 'GET': + return getTransactionsAll(request) + else: + return HttpResponse('Bad Request Method') + +def triggers(request, userID): + if request.method == 'GET': + return getUserTriggers(request, userID) + elif request.method == 'POST': + return addTrigger(request, userID) + else: + return HttpResponse('Bad Request Method') + +def trigger(request, id): + if request.method == 'GET': + return getTrigger(request, id) + if request.method == 'PUT': + return putTrigger(request, id) + elif request.method == 'DELETE': + return deleteTrigger(request, id) + else: + return HttpResponse('Bad Request Method') + +def triggersAll(request): + if request.method == 'GET': + return getTriggersAll(request) + else: + return HttpResponse('Bad Request Method') + +def notifications(request, userID): + if request.method == 'GET': + return getUserNotifications(request, userID) + else: + return HttpResponse('Bad Request Method') + +def notification(request, id): + if request.method == 'DELETE': + return deleteNotification(request, id) + else: + return HttpResponse('Bad Request Method') diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..d1264ec --- /dev/null +++ b/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TradeApp.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..51f9ce1 --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ + +sudo docker run -p 6379:6379 -d redis:5 +python3 manage.py runserver 9090 +exit $? \ No newline at end of file diff --git a/testGraph.txt b/testGraph.txt new file mode 100644 index 0000000..d24757d --- /dev/null +++ b/testGraph.txt @@ -0,0 +1 @@ +{"candles": [{"Open": 31090.0, "Close": 31150.0, "Max": 31150.0, "Min": 31072.0, "Volume": 83.69864705, "Date": "2020-01-11 20:00:00"}, {"Open": 31135.79, "Close": 31140.0, "Max": 31150.0, "Min": 31050.0, "Volume": 98.74688844, "Date": "2020-01-11 20:30:00"}, {"Open": 31140.0, "Close": 31147.99, "Max": 31148.98, "Min": 31100.0, "Volume": 0.47959552, "Date": "2020-01-11 21:00:00"}, {"Open": 31147.99, "Close": 30997.59, "Max": 31353.0, "Min": 30767.49, "Volume": 55.58070245, "Date": "2020-01-11 21:30:00"}, {"Open": 30997.54, "Close": 30857.69, "Max": 30997.55, "Min": 30660.0, "Volume": 97.43097249, "Date": "2020-01-11 22:00:00"}, {"Open": 30852.04, "Close": 30819.5, "Max": 30922.56, "Min": 30705.01, "Volume": 2.19461501, "Date": "2020-01-11 22:30:00"}, {"Open": 30706.02, "Close": 30700.0, "Max": 30840.52, "Min": 30700.0, "Volume": 11.26341727, "Date": "2020-01-11 23:00:00"}, {"Open": 30700.0, "Close": 30653.09, "Max": 30802.47, "Min": 30570.0, "Volume": 66.47023779, "Date": "2020-01-11 23:30:00"}, {"Open": 30580.0, "Close": 30709.98, "Max": 30710.0, "Min": 30450.0, "Volume": 85.46835314, "Date": "2020-01-12 00:00:00"}, {"Open": 30693.8, "Close": 30821.37, "Max": 30830.28, "Min": 30664.56, "Volume": 0.1643201, "Date": "2020-01-12 00:30:00"}, {"Open": 30797.89, "Close": 30777.8, "Max": 30847.45, "Min": 30702.01, "Volume": 57.02058524, "Date": "2020-01-12 01:00:00"}, {"Open": 30777.08, "Close": 30786.64, "Max": 30882.45, "Min": 30776.73, "Volume": 2.75756843, "Date": "2020-01-12 01:30:00"}, {"Open": 30775.12, "Close": 30745.0, "Max": 30780.92, "Min": 30663.39, "Volume": 16.62436649, "Date": "2020-01-12 02:00:00"}, {"Open": 30745.0, "Close": 30751.62, "Max": 30929.03, "Min": 30745.0, "Volume": 31.65647486, "Date": "2020-01-12 02:30:00"}, {"Open": 30771.97, "Close": 30778.46, "Max": 30921.9, "Min": 30746.23, "Volume": 52.77955865, "Date": "2020-01-12 03:00:00"}, {"Open": 30859.04, "Close": 30746.26, "Max": 30876.24, "Min": 30746.26, "Volume": 0.01241428, "Date": "2020-01-12 03:30:00"}, {"Open": 30852.19, "Close": 30898.63, "Max": 30915.0, "Min": 30767.63, "Volume": 49.14441159, "Date": "2020-01-12 04:00:00"}, {"Open": 30914.53, "Close": 30843.56, "Max": 30914.53, "Min": 30727.48, "Volume": 0.04327263, "Date": "2020-01-12 04:30:00"}, {"Open": 30780.89, "Close": 30872.06, "Max": 30888.0, "Min": 30775.79, "Volume": 49.33392522, "Date": "2020-01-12 05:00:00"}, {"Open": 30824.93, "Close": 30888.0, "Max": 30888.0, "Min": 30723.88, "Volume": 37.22308216, "Date": "2020-01-12 05:30:00"}, {"Open": 30730.76, "Close": 31068.05, "Max": 31099.98, "Min": 30730.76, "Volume": 98.29251354, "Date": "2020-01-12 06:00:00"}, {"Open": 30981.45, "Close": 30944.84, "Max": 31019.41, "Min": 30912.25, "Volume": 16.58028944, "Date": "2020-01-12 06:30:00"}, {"Open": 30929.45, "Close": 30875.0, "Max": 30929.45, "Min": 30864.8, "Volume": 35.57468971, "Date": "2020-01-12 07:00:00"}, {"Open": 30875.0, "Close": 30926.11, "Max": 30969.97, "Min": 30784.39, "Volume": 33.59614461, "Date": "2020-01-12 07:30:00"}, {"Open": 30926.1, "Close": 31000.0, "Max": 31000.0, "Min": 30770.6, "Volume": 42.00316365, "Date": "2020-01-12 08:00:00"}, {"Open": 31000.0, "Close": 31000.0, "Max": 31000.0, "Min": 30890.26, "Volume": 36.47100562, "Date": "2020-01-12 08:30:00"}, {"Open": 31000.0, "Close": 31100.0, "Max": 31100.0, "Min": 30952.47, "Volume": 25.28336602, "Date": "2020-01-12 09:00:00"}, {"Open": 31100.0, "Close": 30989.61, "Max": 31100.0, "Min": 30989.6, "Volume": 24.66432031, "Date": "2020-01-12 09:30:00"}, {"Open": 31000.0, "Close": 30955.0, "Max": 31000.0, "Min": 30900.0, "Volume": 51.11043445, "Date": "2020-01-12 10:00:00"}, {"Open": 30955.0, "Close": 30954.0, "Max": 30955.0, "Min": 30902.0, "Volume": 4.01944326, "Date": "2020-01-12 10:30:00"}, {"Open": 30954.0, "Close": 30999.93, "Max": 31000.0, "Min": 30844.16, "Volume": 64.22182095, "Date": "2020-01-12 11:00:00"}, {"Open": 30999.93, "Close": 30974.94, "Max": 31000.0, "Min": 30870.0, "Volume": 0.30499842, "Date": "2020-01-12 11:30:00"}, {"Open": 30974.93, "Close": 31034.99, "Max": 31049.98, "Min": 30870.0, "Volume": 56.97751381, "Date": "2020-01-12 12:00:00"}, {"Open": 31035.0, "Close": 31071.33, "Max": 31095.5, "Min": 30885.13, "Volume": 9.14756352, "Date": "2020-01-12 12:30:00"}, {"Open": 31071.33, "Close": 31033.0, "Max": 31071.33, "Min": 30918.73, "Volume": 22.84543636, "Date": "2020-01-12 13:00:00"}, {"Open": 31032.99, "Close": 31090.0, "Max": 31100.0, "Min": 30911.6, "Volume": 18.52646709, "Date": "2020-01-12 13:30:00"}, {"Open": 31090.0, "Close": 31111.02, "Max": 31198.99, "Min": 30991.05, "Volume": 24.46334917, "Date": "2020-01-12 14:00:00"}, {"Open": 31111.0, "Close": 31088.07, "Max": 31111.0, "Min": 30959.39, "Volume": 34.74964329, "Date": "2020-01-12 14:30:00"}, {"Open": 31088.05, "Close": 31093.0, "Max": 31093.0, "Min": 31017.73, "Volume": 22.86843902, "Date": "2020-01-12 15:00:00"}, {"Open": 31093.0, "Close": 31092.99, "Max": 31093.0, "Min": 31031.77, "Volume": 19.85899872, "Date": "2020-01-12 15:30:00"}, {"Open": 31092.99, "Close": 31090.0, "Max": 31092.99, "Min": 30984.78, "Volume": 22.37810785, "Date": "2020-01-12 16:00:00"}, {"Open": 31079.0, "Close": 30948.58, "Max": 31079.0, "Min": 30871.03, "Volume": 18.12199469, "Date": "2020-01-12 16:30:00"}, {"Open": 30900.0, "Close": 31079.87, "Max": 31093.0, "Min": 30824.58, "Volume": 19.61834984, "Date": "2020-01-12 17:00:00"}, {"Open": 31079.67, "Close": 30967.29, "Max": 31079.67, "Min": 30809.27, "Volume": 13.48341491, "Date": "2020-01-12 17:30:00"}, {"Open": 30929.8, "Close": 30940.0, "Max": 30971.14, "Min": 30886.53, "Volume": 9.68353688, "Date": "2020-01-12 18:00:00"}, {"Open": 30940.0, "Close": 30940.0, "Max": 30940.0, "Min": 30864.35, "Volume": 10.30357678, "Date": "2020-01-12 18:30:00"}, {"Open": 30940.0, "Close": 31028.92, "Max": 31050.0, "Min": 30881.42, "Volume": 21.58807229, "Date": "2020-01-12 19:00:00"}, {"Open": 31020.0, "Close": 30968.0, "Max": 31020.0, "Min": 30894.41, "Volume": 42.54429655, "Date": "2020-01-12 19:30:00"}, {"Open": 30968.0, "Close": 31089.69, "Max": 31099.97, "Min": 30965.44, "Volume": 19.8954233, "Date": "2020-01-12 20:00:00"}, {"Open": 31089.68, "Close": 31050.0, "Max": 31098.98, "Min": 30965.44, "Volume": 11.61762663, "Date": "2020-01-12 20:30:00"}, {"Open": 31050.0, "Close": 31045.0, "Max": 31050.0, "Min": 30952.2, "Volume": 48.38108663, "Date": "2020-01-12 21:00:00"}, {"Open": 31045.0, "Close": 30967.25, "Max": 31049.0, "Min": 30921.58, "Volume": 25.07674092, "Date": "2020-01-12 21:30:00"}, {"Open": 30976.82, "Close": 30998.19, "Max": 31049.77, "Min": 30700.01, "Volume": 82.84647021, "Date": "2020-01-12 22:00:00"}, {"Open": 31046.88, "Close": 31068.98, "Max": 31075.0, "Min": 30957.21, "Volume": 3.48328786, "Date": "2020-01-12 22:30:00"}, {"Open": 31068.98, "Close": 31109.97, "Max": 31150.0, "Min": 31053.96, "Volume": 49.85778027, "Date": "2020-01-12 23:00:00"}, {"Open": 31110.0, "Close": 31200.0, "Max": 31200.0, "Min": 31043.81, "Volume": 15.20422786, "Date": "2020-01-12 23:30:00"}, {"Open": 31200.0, "Close": 31161.5, "Max": 31300.0, "Min": 31065.36, "Volume": 30.65032052, "Date": "2020-01-13 00:00:00"}, {"Open": 31082.78, "Close": 31045.97, "Max": 31214.94, "Min": 31016.72, "Volume": 28.42423382, "Date": "2020-01-13 00:30:00"}, {"Open": 31074.85, "Close": 31050.62, "Max": 31074.85, "Min": 31046.33, "Volume": 23.88616036, "Date": "2020-01-13 01:00:00"}, {"Open": 31050.8, "Close": 31074.85, "Max": 31074.85, "Min": 31049.4, "Volume": 14.37152331, "Date": "2020-01-13 01:30:00"}, {"Open": 31047.78, "Close": 31036.74, "Max": 31048.13, "Min": 31036.74, "Volume": 25.6769379, "Date": "2020-01-13 02:00:00"}, {"Open": 31024.24, "Close": 30990.62, "Max": 31043.82, "Min": 30947.69, "Volume": 6.19950688, "Date": "2020-01-13 02:30:00"}, {"Open": 30970.0, "Close": 30900.0, "Max": 30973.5, "Min": 30900.0, "Volume": 32.713999, "Date": "2020-01-13 03:00:00"}, {"Open": 30850.17, "Close": 30949.97, "Max": 30950.28, "Min": 30832.82, "Volume": 31.429126, "Date": "2020-01-13 03:30:00"}, {"Open": 30848.16, "Close": 30863.67, "Max": 30880.38, "Min": 30847.38, "Volume": 36.71182422, "Date": "2020-01-13 04:00:00"}, {"Open": 30911.28, "Close": 30938.65, "Max": 30938.85, "Min": 30819.08, "Volume": 10.22732675, "Date": "2020-01-13 04:30:00"}, {"Open": 30938.06, "Close": 30881.35, "Max": 30938.06, "Min": 30806.56, "Volume": 0.121225, "Date": "2020-01-13 05:00:00"}, {"Open": 30850.0, "Close": 30819.11, "Max": 30850.0, "Min": 30800.0, "Volume": 0.3189036, "Date": "2020-01-13 05:30:00"}, {"Open": 30819.11, "Close": 30886.8, "Max": 30920.01, "Min": 30801.79, "Volume": 26.0479585, "Date": "2020-01-13 06:00:00"}, {"Open": 30850.0, "Close": 30611.21, "Max": 30851.85, "Min": 30600.01, "Volume": 49.47062423, "Date": "2020-01-13 06:30:00"}, {"Open": 30728.48, "Close": 30711.21, "Max": 30770.19, "Min": 30647.47, "Volume": 89.82562266, "Date": "2020-01-13 07:00:00"}, {"Open": 30733.38, "Close": 30770.0, "Max": 30825.8, "Min": 30671.0, "Volume": 82.00119679, "Date": "2020-01-13 07:30:00"}, {"Open": 30805.01, "Close": 30897.11, "Max": 30897.11, "Min": 30651.23, "Volume": 16.23079517, "Date": "2020-01-13 08:00:00"}, {"Open": 30825.0, "Close": 30935.66, "Max": 30935.99, "Min": 30744.17, "Volume": 1.98609253, "Date": "2020-01-13 08:30:00"}, {"Open": 30935.99, "Close": 30899.74, "Max": 30951.78, "Min": 30779.97, "Volume": 0.23393462, "Date": "2020-01-13 09:00:00"}, {"Open": 30899.71, "Close": 30914.15, "Max": 30943.41, "Min": 30781.78, "Volume": 58.5851238, "Date": "2020-01-13 09:30:00"}, {"Open": 30943.64, "Close": 30930.0, "Max": 30943.64, "Min": 30864.24, "Volume": 2.37808346, "Date": "2020-01-13 10:00:00"}, {"Open": 30930.0, "Close": 30910.0, "Max": 30966.0, "Min": 30825.05, "Volume": 50.98999147, "Date": "2020-01-13 10:30:00"}, {"Open": 30910.0, "Close": 30940.0, "Max": 30999.99, "Min": 30882.58, "Volume": 2.13565825, "Date": "2020-01-13 11:00:00"}, {"Open": 30940.0, "Close": 30875.08, "Max": 30940.0, "Min": 30844.43, "Volume": 0.78327151, "Date": "2020-01-13 11:30:00"}, {"Open": 30853.16, "Close": 30753.51, "Max": 30853.16, "Min": 30701.69, "Volume": 2.75751171, "Date": "2020-01-13 12:00:00"}, {"Open": 30817.99, "Close": 30801.3, "Max": 30849.77, "Min": 30730.0, "Volume": 1.60986353, "Date": "2020-01-13 12:30:00"}, {"Open": 30801.3, "Close": 30883.21, "Max": 30890.99, "Min": 30800.0, "Volume": 34.79195197, "Date": "2020-01-13 13:00:00"}, {"Open": 30883.21, "Close": 30847.82, "Max": 30886.94, "Min": 30749.9, "Volume": 36.51017572, "Date": "2020-01-13 13:30:00"}, {"Open": 30847.82, "Close": 30818.06, "Max": 30877.18, "Min": 30767.54, "Volume": 17.35219138, "Date": "2020-01-13 14:00:00"}, {"Open": 30818.06, "Close": 30874.99, "Max": 30891.42, "Min": 30750.0, "Volume": 23.1864501, "Date": "2020-01-13 14:30:00"}, {"Open": 30863.78, "Close": 30828.94, "Max": 30900.0, "Min": 30755.8, "Volume": 46.6067205, "Date": "2020-01-13 15:00:00"}, {"Open": 30828.81, "Close": 30738.83, "Max": 30900.0, "Min": 30683.93, "Volume": 50.80004987, "Date": "2020-01-13 15:30:00"}, {"Open": 30738.83, "Close": 30798.84, "Max": 30871.76, "Min": 30699.44, "Volume": 50.11406126, "Date": "2020-01-13 16:00:00"}, {"Open": 30789.43, "Close": 30825.78, "Max": 30825.78, "Min": 30739.03, "Volume": 5.73508711, "Date": "2020-01-13 16:30:00"}, {"Open": 30825.78, "Close": 30870.5, "Max": 30937.91, "Min": 30778.79, "Volume": 52.72385607, "Date": "2020-01-13 17:00:00"}, {"Open": 30850.15, "Close": 30805.74, "Max": 30934.63, "Min": 30740.3, "Volume": 8.39852519, "Date": "2020-01-13 17:30:00"}, {"Open": 30808.01, "Close": 30802.27, "Max": 30873.49, "Min": 30740.33, "Volume": 54.14579375, "Date": "2020-01-13 18:00:00"}, {"Open": 30802.27, "Close": 30830.58, "Max": 30830.58, "Min": 30750.51, "Volume": 3.65744069, "Date": "2020-01-13 18:30:00"}, {"Open": 30830.58, "Close": 30866.18, "Max": 30866.68, "Min": 30750.1, "Volume": 50.81925828, "Date": "2020-01-13 19:00:00"}, {"Open": 30866.18, "Close": 30862.95, "Max": 30896.81, "Min": 30830.03, "Volume": 3.05041528, "Date": "2020-01-13 19:30:00"}, {"Open": 30862.93, "Close": 30910.99, "Max": 30938.17, "Min": 30801.0, "Volume": 45.74285358, "Date": "2020-01-13 20:00:00"}, {"Open": 30910.99, "Close": 30995.55, "Max": 31000.0, "Min": 30832.36, "Volume": 3.06251588, "Date": "2020-01-13 20:30:00"}, {"Open": 30966.37, "Close": 30964.97, "Max": 31000.0, "Min": 30950.0, "Volume": 29.77511646, "Date": "2020-01-13 21:00:00"}, {"Open": 30964.97, "Close": 30982.03, "Max": 31073.57, "Min": 30917.15, "Volume": 25.92082335, "Date": "2020-01-13 21:30:00"}, {"Open": 30992.48, "Close": 30910.9, "Max": 30994.38, "Min": 30905.78, "Volume": 31.15721052, "Date": "2020-01-13 22:00:00"}, {"Open": 30914.71, "Close": 30906.25, "Max": 30954.52, "Min": 30905.77, "Volume": 35.54177048, "Date": "2020-01-13 22:30:00"}, {"Open": 30906.25, "Close": 30953.43, "Max": 30973.43, "Min": 30895.0, "Volume": 34.79974459, "Date": "2020-01-13 23:00:00"}, {"Open": 30898.98, "Close": 30851.02, "Max": 30958.19, "Min": 30800.01, "Volume": 71.58615858, "Date": "2020-01-13 23:30:00"}, {"Open": 30861.53, "Close": 31000.29, "Max": 31000.29, "Min": 30861.53, "Volume": 49.29568211, "Date": "2020-01-14 00:00:00"}, {"Open": 31011.9, "Close": 31368.76, "Max": 31524.5, "Min": 31011.9, "Volume": 132.39281646, "Date": "2020-01-14 00:30:00"}, {"Open": 31429.1, "Close": 31721.26, "Max": 31879.99, "Min": 31429.1, "Volume": 134.0003886, "Date": "2020-01-14 01:00:00"}, {"Open": 31789.47, "Close": 32079.21, "Max": 32100.0, "Min": 31694.44, "Volume": 146.58678812, "Date": "2020-01-14 01:30:00"}, {"Open": 32072.76, "Close": 31751.07, "Max": 32072.76, "Min": 31705.39, "Volume": 116.26064932, "Date": "2020-01-14 02:00:00"}, {"Open": 31887.99, "Close": 32029.91, "Max": 32029.91, "Min": 31821.32, "Volume": 37.02260688, "Date": "2020-01-14 02:30:00"}, {"Open": 31980.28, "Close": 31713.35, "Max": 31994.67, "Min": 31710.87, "Volume": 41.10052952, "Date": "2020-01-14 03:00:00"}, {"Open": 31794.46, "Close": 32004.0, "Max": 32004.0, "Min": 31794.46, "Volume": 29.26621358, "Date": "2020-01-14 03:30:00"}, {"Open": 32004.0, "Close": 32335.0, "Max": 32350.0, "Min": 32004.0, "Volume": 153.67212001, "Date": "2020-01-14 04:00:00"}, {"Open": 32332.54, "Close": 32330.0, "Max": 32500.0, "Min": 32330.0, "Volume": 64.77235855, "Date": "2020-01-14 04:30:00"}, {"Open": 32400.02, "Close": 32398.99, "Max": 32498.5, "Min": 32227.35, "Volume": 10.31902208, "Date": "2020-01-14 05:00:00"}, {"Open": 32399.0, "Close": 32198.0, "Max": 32438.54, "Min": 32000.1, "Volume": 8.0216314, "Date": "2020-01-14 05:30:00"}, {"Open": 32140.95, "Close": 32210.01, "Max": 32321.5, "Min": 32140.95, "Volume": 77.72804472, "Date": "2020-01-14 06:00:00"}, {"Open": 32235.32, "Close": 32220.0, "Max": 32350.21, "Min": 32170.03, "Volume": 51.753819, "Date": "2020-01-14 06:30:00"}, {"Open": 32280.99, "Close": 32364.67, "Max": 32400.0, "Min": 32170.08, "Volume": 66.56717874, "Date": "2020-01-14 07:00:00"}, {"Open": 32171.94, "Close": 32383.65, "Max": 32400.0, "Min": 32171.94, "Volume": 29.385695, "Date": "2020-01-14 07:30:00"}, {"Open": 32175.0, "Close": 32344.0, "Max": 32372.0, "Min": 32174.97, "Volume": 31.56207259, "Date": "2020-01-14 08:00:00"}, {"Open": 32342.99, "Close": 32291.99, "Max": 32342.99, "Min": 32224.23, "Volume": 58.92939208, "Date": "2020-01-14 08:30:00"}, {"Open": 32291.99, "Close": 32295.0, "Max": 32297.99, "Min": 32173.16, "Volume": 45.66876063, "Date": "2020-01-14 09:00:00"}, {"Open": 32295.0, "Close": 32195.47, "Max": 32297.99, "Min": 32170.06, "Volume": 38.38855525, "Date": "2020-01-14 09:30:00"}, {"Open": 32248.99, "Close": 32104.98, "Max": 32295.44, "Min": 32100.0, "Volume": 36.20415046, "Date": "2020-01-14 10:00:00"}, {"Open": 32104.98, "Close": 32284.7, "Max": 32284.99, "Min": 31900.03, "Volume": 8.22061298, "Date": "2020-01-14 10:30:00"}, {"Open": 32284.69, "Close": 31820.42, "Max": 32285.0, "Min": 31800.04, "Volume": 87.57580561, "Date": "2020-01-14 11:00:00"}, {"Open": 32136.3, "Close": 32100.01, "Max": 32136.3, "Min": 31820.74, "Volume": 13.99541909, "Date": "2020-01-14 11:30:00"}, {"Open": 32100.01, "Close": 32248.0, "Max": 32269.98, "Min": 32100.0, "Volume": 127.86384558, "Date": "2020-01-14 12:00:00"}, {"Open": 32248.0, "Close": 32190.39, "Max": 32498.99, "Min": 32100.0, "Volume": 32.7296336, "Date": "2020-01-14 12:30:00"}, {"Open": 32190.37, "Close": 32398.89, "Max": 32398.89, "Min": 32150.01, "Volume": 86.50232537, "Date": "2020-01-14 13:00:00"}, {"Open": 32398.99, "Close": 32495.38, "Max": 32497.11, "Min": 32283.0, "Volume": 10.48228624, "Date": "2020-01-14 13:30:00"}, {"Open": 32495.38, "Close": 32999.97, "Max": 33000.0, "Min": 32288.51, "Volume": 117.42275644, "Date": "2020-01-14 14:00:00"}, {"Open": 32999.96, "Close": 32900.01, "Max": 33199.98, "Min": 32699.04, "Volume": 100.97595796, "Date": "2020-01-14 14:30:00"}, {"Open": 32919.68, "Close": 33000.0, "Max": 33000.0, "Min": 32703.69, "Volume": 159.76691621, "Date": "2020-01-14 15:00:00"}, {"Open": 33000.0, "Close": 33046.18, "Max": 33079.97, "Min": 32852.9, "Volume": 118.72440166, "Date": "2020-01-14 15:30:00"}, {"Open": 32996.58, "Close": 32525.83, "Max": 33035.62, "Min": 32300.53, "Volume": 18.3070231, "Date": "2020-01-14 16:00:00"}, {"Open": 32524.99, "Close": 32673.77, "Max": 32939.38, "Min": 32360.0, "Volume": 93.17250567, "Date": "2020-01-14 16:30:00"}, {"Open": 32673.77, "Close": 33023.65, "Max": 33142.44, "Min": 32673.77, "Volume": 123.82239412, "Date": "2020-01-14 17:00:00"}, {"Open": 33041.99, "Close": 33249.98, "Max": 33398.99, "Min": 32850.02, "Volume": 50.71209703, "Date": "2020-01-14 17:30:00"}, {"Open": 33249.98, "Close": 33447.21, "Max": 33447.26, "Min": 33102.03, "Volume": 181.67455038, "Date": "2020-01-14 18:00:00"}, {"Open": 33438.31, "Close": 33212.49, "Max": 33450.0, "Min": 32900.01, "Volume": 5.34780429, "Date": "2020-01-14 18:30:00"}, {"Open": 33212.49, "Close": 33084.99, "Max": 33266.92, "Min": 32900.01, "Volume": 133.66388363, "Date": "2020-01-14 19:00:00"}, {"Open": 33069.99, "Close": 32921.05, "Max": 33090.0, "Min": 32900.03, "Volume": 68.13319656, "Date": "2020-01-14 19:30:00"}, {"Open": 33088.99, "Close": 33032.89, "Max": 33089.0, "Min": 32921.12, "Volume": 126.63226688, "Date": "2020-01-14 20:00:00"}, {"Open": 33032.89, "Close": 32947.95, "Max": 33060.0, "Min": 32700.12, "Volume": 14.21573713, "Date": "2020-01-14 20:30:00"}, {"Open": 32944.98, "Close": 32896.03, "Max": 32944.98, "Min": 32717.11, "Volume": 67.35503797, "Date": "2020-01-14 21:00:00"}, {"Open": 32896.03, "Close": 32940.58, "Max": 33050.0, "Min": 32896.02, "Volume": 46.68565275, "Date": "2020-01-14 21:30:00"}, {"Open": 32940.58, "Close": 33059.99, "Max": 33060.0, "Min": 32899.98, "Volume": 60.64368603, "Date": "2020-01-14 22:00:00"}, {"Open": 33058.99, "Close": 33059.98, "Max": 33060.0, "Min": 32998.99, "Volume": 13.78857534, "Date": "2020-01-14 22:30:00"}, {"Open": 33059.98, "Close": 33100.0, "Max": 33100.0, "Min": 32998.99, "Volume": 44.6759928, "Date": "2020-01-14 23:00:00"}, {"Open": 33128.2, "Close": 33304.52, "Max": 33520.0, "Min": 33030.02, "Volume": 226.59739768, "Date": "2020-01-14 23:30:00"}, {"Open": 33227.31, "Close": 33369.05, "Max": 33480.0, "Min": 32900.0, "Volume": 126.09650636, "Date": "2020-01-15 00:00:00"}, {"Open": 33479.99, "Close": 33106.76, "Max": 33479.99, "Min": 32900.01, "Volume": 150.26999975, "Date": "2020-01-15 00:30:00"}, {"Open": 33106.75, "Close": 32856.98, "Max": 33247.86, "Min": 32800.0, "Volume": 179.21401128, "Date": "2020-01-15 01:00:00"}, {"Open": 32868.36, "Close": 33081.61, "Max": 33157.33, "Min": 32800.06, "Volume": 124.37461203, "Date": "2020-01-15 01:30:00"}, {"Open": 33083.85, "Close": 33264.74, "Max": 33296.94, "Min": 32950.03, "Volume": 106.31521555, "Date": "2020-01-15 02:00:00"}, {"Open": 33264.2, "Close": 33239.39, "Max": 33264.2, "Min": 32960.0, "Volume": 47.61557527, "Date": "2020-01-15 02:30:00"}, {"Open": 33236.75, "Close": 33198.68, "Max": 33236.86, "Min": 33027.6, "Volume": 107.83399395, "Date": "2020-01-15 03:00:00"}, {"Open": 33164.63, "Close": 32999.09, "Max": 33198.06, "Min": 32810.01, "Volume": 45.05741621, "Date": "2020-01-15 03:30:00"}, {"Open": 32998.75, "Close": 32483.0, "Max": 32998.75, "Min": 32483.0, "Volume": 26.28861685, "Date": "2020-01-15 04:00:00"}, {"Open": 32480.01, "Close": 32599.74, "Max": 32715.25, "Min": 32450.0, "Volume": 123.74892433, "Date": "2020-01-15 04:30:00"}, {"Open": 32500.11, "Close": 32549.99, "Max": 32675.42, "Min": 32399.98, "Volume": 2.31334318, "Date": "2020-01-15 05:00:00"}, {"Open": 32400.01, "Close": 32270.0, "Max": 32550.0, "Min": 32267.02, "Volume": 14.76365909, "Date": "2020-01-15 05:30:00"}, {"Open": 32546.01, "Close": 32445.0, "Max": 32546.01, "Min": 32270.0, "Volume": 0.7646701, "Date": "2020-01-15 06:00:00"}, {"Open": 32445.0, "Close": 32620.01, "Max": 32621.89, "Min": 32310.01, "Volume": 7.48756148, "Date": "2020-01-15 06:30:00"}, {"Open": 32620.01, "Close": 32610.01, "Max": 32621.89, "Min": 32604.99, "Volume": 7.24294268, "Date": "2020-01-15 07:00:00"}, {"Open": 32610.01, "Close": 32449.99, "Max": 32610.01, "Min": 32348.0, "Volume": 74.58734283, "Date": "2020-01-15 07:30:00"}, {"Open": 32449.98, "Close": 32574.98, "Max": 32574.99, "Min": 32300.01, "Volume": 15.38745243, "Date": "2020-01-15 08:00:00"}, {"Open": 32574.98, "Close": 32562.95, "Max": 32574.99, "Min": 32400.01, "Volume": 51.72283559, "Date": "2020-01-15 08:30:00"}, {"Open": 32562.99, "Close": 32596.65, "Max": 32604.38, "Min": 32375.0, "Volume": 38.4271044, "Date": "2020-01-15 09:00:00"}, {"Open": 32596.62, "Close": 32999.7, "Max": 32999.88, "Min": 32375.01, "Volume": 6.27617116, "Date": "2020-01-15 09:30:00"}, {"Open": 32999.7, "Close": 32996.99, "Max": 33049.99, "Min": 32705.05, "Volume": 25.35192695, "Date": "2020-01-15 10:00:00"}, {"Open": 32996.99, "Close": 33187.97, "Max": 33187.99, "Min": 32900.0, "Volume": 44.95076789, "Date": "2020-01-15 10:30:00"}, {"Open": 33187.97, "Close": 33043.98, "Max": 33187.97, "Min": 32979.5, "Volume": 1.73455037, "Date": "2020-01-15 11:00:00"}, {"Open": 33043.98, "Close": 32998.07, "Max": 33043.98, "Min": 32900.0, "Volume": 7.79481189, "Date": "2020-01-15 11:30:00"}, {"Open": 32998.07, "Close": 32990.0, "Max": 32999.0, "Min": 32800.01, "Volume": 13.3931099, "Date": "2020-01-15 12:00:00"}, {"Open": 32990.0, "Close": 32966.52, "Max": 33000.0, "Min": 32862.66, "Volume": 154.10978063, "Date": "2020-01-15 12:30:00"}, {"Open": 32873.81, "Close": 33100.02, "Max": 33197.0, "Min": 32873.8, "Volume": 10.35398222, "Date": "2020-01-15 13:00:00"}, {"Open": 33100.02, "Close": 33399.99, "Max": 33399.99, "Min": 33100.0, "Volume": 23.40399744, "Date": "2020-01-15 13:30:00"}, {"Open": 33399.99, "Close": 33299.99, "Max": 33489.99, "Min": 33102.01, "Volume": 9.06890721, "Date": "2020-01-15 14:00:00"}, {"Open": 33299.99, "Close": 33399.81, "Max": 33489.97, "Min": 33143.93, "Volume": 94.30600321, "Date": "2020-01-15 14:30:00"}, {"Open": 33399.7, "Close": 33207.79, "Max": 33399.73, "Min": 32916.65, "Volume": 51.39760061, "Date": "2020-01-15 15:00:00"}, {"Open": 33207.78, "Close": 33083.95, "Max": 33207.84, "Min": 33001.0, "Volume": 61.55392306, "Date": "2020-01-15 15:30:00"}, {"Open": 33083.95, "Close": 33184.99, "Max": 33199.69, "Min": 32873.8, "Volume": 98.51673779, "Date": "2020-01-15 16:00:00"}, {"Open": 33184.99, "Close": 33138.02, "Max": 33224.68, "Min": 33007.66, "Volume": 1.80367129, "Date": "2020-01-15 16:30:00"}, {"Open": 33180.99, "Close": 32865.21, "Max": 33202.26, "Min": 32498.94, "Volume": 113.00296892, "Date": "2020-01-15 17:00:00"}, {"Open": 32938.4, "Close": 32989.98, "Max": 33118.35, "Min": 32666.03, "Volume": 2.7169386, "Date": "2020-01-15 17:30:00"}, {"Open": 32989.99, "Close": 32752.27, "Max": 32989.99, "Min": 32600.0, "Volume": 18.48685506, "Date": "2020-01-15 18:00:00"}, {"Open": 32754.53, "Close": 32800.0, "Max": 32989.99, "Min": 32700.0, "Volume": 46.87518283, "Date": "2020-01-15 18:30:00"}, {"Open": 32844.98, "Close": 32969.69, "Max": 32989.99, "Min": 32844.96, "Volume": 58.73300902, "Date": "2020-01-15 19:00:00"}, {"Open": 32969.68, "Close": 32900.0, "Max": 32969.69, "Min": 32860.0, "Volume": 1.13034249, "Date": "2020-01-15 19:30:00"}, {"Open": 32900.0, "Close": 32899.95, "Max": 32900.0, "Min": 32859.84, "Volume": 54.38986651, "Date": "2020-01-15 20:00:00"}, {"Open": 32899.95, "Close": 33129.65, "Max": 33149.98, "Min": 32859.84, "Volume": 2.43989605, "Date": "2020-01-15 20:30:00"}, {"Open": 33129.44, "Close": 33199.77, "Max": 33200.0, "Min": 32920.1, "Volume": 36.5356959, "Date": "2020-01-15 21:00:00"}, {"Open": 33199.77, "Close": 33189.03, "Max": 33199.79, "Min": 32920.06, "Volume": 54.57189256, "Date": "2020-01-15 21:30:00"}, {"Open": 33189.02, "Close": 33096.82, "Max": 33194.99, "Min": 32920.25, "Volume": 36.91199134, "Date": "2020-01-15 22:00:00"}, {"Open": 33096.82, "Close": 33200.0, "Max": 33200.0, "Min": 33000.04, "Volume": 12.9130503, "Date": "2020-01-15 22:30:00"}, {"Open": 33200.0, "Close": 33100.0, "Max": 33248.97, "Min": 33011.5, "Volume": 42.1483899, "Date": "2020-01-15 23:00:00"}, {"Open": 33100.0, "Close": 33145.09, "Max": 33199.97, "Min": 33081.06, "Volume": 6.58223194, "Date": "2020-01-15 23:30:00"}], "candlesCount": 199, "graphMin": 30450.0, "graphMax": 33520.0} diff --git a/testGraph2.txt b/testGraph2.txt new file mode 100644 index 0000000..3977ef2 --- /dev/null +++ b/testGraph2.txt @@ -0,0 +1 @@ +{"candles": [{"Open": 30818.06, "Close": 30874.99, "Max": 30891.42, "Min": 30750.0, "Volume": 23.1864501, "Date": "2020-01-13 14:30:00"}, {"Open": 30863.78, "Close": 30828.94, "Max": 30900.0, "Min": 30755.8, "Volume": 46.6067205, "Date": "2020-01-13 15:00:00"}, {"Open": 30828.81, "Close": 30738.83, "Max": 30900.0, "Min": 30683.93, "Volume": 50.80004987, "Date": "2020-01-13 15:30:00"}, {"Open": 30738.83, "Close": 30798.84, "Max": 30871.76, "Min": 30699.44, "Volume": 50.11406126, "Date": "2020-01-13 16:00:00"}, {"Open": 30789.43, "Close": 30825.78, "Max": 30825.78, "Min": 30739.03, "Volume": 5.73508711, "Date": "2020-01-13 16:30:00"}, {"Open": 30825.78, "Close": 30870.5, "Max": 30937.91, "Min": 30778.79, "Volume": 52.72385607, "Date": "2020-01-13 17:00:00"}, {"Open": 30850.15, "Close": 30805.74, "Max": 30934.63, "Min": 30740.3, "Volume": 8.39852519, "Date": "2020-01-13 17:30:00"}, {"Open": 30808.01, "Close": 30802.27, "Max": 30873.49, "Min": 30740.33, "Volume": 54.14579375, "Date": "2020-01-13 18:00:00"}, {"Open": 30802.27, "Close": 30830.58, "Max": 30830.58, "Min": 30750.51, "Volume": 3.65744069, "Date": "2020-01-13 18:30:00"}, {"Open": 30830.58, "Close": 30866.18, "Max": 30866.68, "Min": 30750.1, "Volume": 50.81925828, "Date": "2020-01-13 19:00:00"}, {"Open": 30866.18, "Close": 30862.95, "Max": 30896.81, "Min": 30830.03, "Volume": 3.05041528, "Date": "2020-01-13 19:30:00"}, {"Open": 30862.93, "Close": 30910.99, "Max": 30938.17, "Min": 30801.0, "Volume": 45.74285358, "Date": "2020-01-13 20:00:00"}, {"Open": 30910.99, "Close": 30995.55, "Max": 31000.0, "Min": 30832.36, "Volume": 3.06251588, "Date": "2020-01-13 20:30:00"}, {"Open": 30966.37, "Close": 30964.97, "Max": 31000.0, "Min": 30950.0, "Volume": 29.77511646, "Date": "2020-01-13 21:00:00"}, {"Open": 30964.97, "Close": 30982.03, "Max": 31073.57, "Min": 30917.15, "Volume": 25.92082335, "Date": "2020-01-13 21:30:00"}, {"Open": 30992.48, "Close": 30910.9, "Max": 30994.38, "Min": 30905.78, "Volume": 31.15721052, "Date": "2020-01-13 22:00:00"}, {"Open": 30914.71, "Close": 30906.25, "Max": 30954.52, "Min": 30905.77, "Volume": 35.54177048, "Date": "2020-01-13 22:30:00"}, {"Open": 30906.25, "Close": 30953.43, "Max": 30973.43, "Min": 30895.0, "Volume": 34.79974459, "Date": "2020-01-13 23:00:00"}, {"Open": 30898.98, "Close": 30851.02, "Max": 30958.19, "Min": 30800.01, "Volume": 71.58615858, "Date": "2020-01-13 23:30:00"}, {"Open": 30861.53, "Close": 31000.29, "Max": 31000.29, "Min": 30861.53, "Volume": 49.29568211, "Date": "2020-01-14 00:00:00"}, {"Open": 31011.9, "Close": 31368.76, "Max": 31524.5, "Min": 31011.9, "Volume": 132.39281646, "Date": "2020-01-14 00:30:00"}, {"Open": 31429.1, "Close": 31721.26, "Max": 31879.99, "Min": 31429.1, "Volume": 134.0003886, "Date": "2020-01-14 01:00:00"}, {"Open": 31789.47, "Close": 32079.21, "Max": 32100.0, "Min": 31694.44, "Volume": 146.58678812, "Date": "2020-01-14 01:30:00"}, {"Open": 32072.76, "Close": 31751.07, "Max": 32072.76, "Min": 31705.39, "Volume": 116.26064932, "Date": "2020-01-14 02:00:00"}, {"Open": 31887.99, "Close": 32029.91, "Max": 32029.91, "Min": 31821.32, "Volume": 37.02260688, "Date": "2020-01-14 02:30:00"}, {"Open": 31980.28, "Close": 31713.35, "Max": 31994.67, "Min": 31710.87, "Volume": 41.10052952, "Date": "2020-01-14 03:00:00"}, {"Open": 31794.46, "Close": 32004.0, "Max": 32004.0, "Min": 31794.46, "Volume": 29.26621358, "Date": "2020-01-14 03:30:00"}, {"Open": 32004.0, "Close": 32335.0, "Max": 32350.0, "Min": 32004.0, "Volume": 153.67212001, "Date": "2020-01-14 04:00:00"}, {"Open": 32332.54, "Close": 32330.0, "Max": 32500.0, "Min": 32330.0, "Volume": 64.77235855, "Date": "2020-01-14 04:30:00"}, {"Open": 32400.02, "Close": 32398.99, "Max": 32498.5, "Min": 32227.35, "Volume": 10.31902208, "Date": "2020-01-14 05:00:00"}, {"Open": 32399.0, "Close": 32198.0, "Max": 32438.54, "Min": 32000.1, "Volume": 8.0216314, "Date": "2020-01-14 05:30:00"}, {"Open": 32140.95, "Close": 32210.01, "Max": 32321.5, "Min": 32140.95, "Volume": 77.72804472, "Date": "2020-01-14 06:00:00"}, {"Open": 32235.32, "Close": 32220.0, "Max": 32350.21, "Min": 32170.03, "Volume": 51.753819, "Date": "2020-01-14 06:30:00"}, {"Open": 32280.99, "Close": 32364.67, "Max": 32400.0, "Min": 32170.08, "Volume": 66.56717874, "Date": "2020-01-14 07:00:00"}, {"Open": 32171.94, "Close": 32383.65, "Max": 32400.0, "Min": 32171.94, "Volume": 29.385695, "Date": "2020-01-14 07:30:00"}, {"Open": 32175.0, "Close": 32344.0, "Max": 32372.0, "Min": 32174.97, "Volume": 31.56207259, "Date": "2020-01-14 08:00:00"}, {"Open": 32342.99, "Close": 32291.99, "Max": 32342.99, "Min": 32224.23, "Volume": 58.92939208, "Date": "2020-01-14 08:30:00"}, {"Open": 32291.99, "Close": 32295.0, "Max": 32297.99, "Min": 32173.16, "Volume": 45.66876063, "Date": "2020-01-14 09:00:00"}, {"Open": 32295.0, "Close": 32195.47, "Max": 32297.99, "Min": 32170.06, "Volume": 38.38855525, "Date": "2020-01-14 09:30:00"}, {"Open": 32248.99, "Close": 32104.98, "Max": 32295.44, "Min": 32100.0, "Volume": 36.20415046, "Date": "2020-01-14 10:00:00"}, {"Open": 32104.98, "Close": 32284.7, "Max": 32284.99, "Min": 31900.03, "Volume": 8.22061298, "Date": "2020-01-14 10:30:00"}, {"Open": 32284.69, "Close": 31820.42, "Max": 32285.0, "Min": 31800.04, "Volume": 87.57580561, "Date": "2020-01-14 11:00:00"}, {"Open": 32136.3, "Close": 32100.01, "Max": 32136.3, "Min": 31820.74, "Volume": 13.99541909, "Date": "2020-01-14 11:30:00"}, {"Open": 32100.01, "Close": 32248.0, "Max": 32269.98, "Min": 32100.0, "Volume": 127.86384558, "Date": "2020-01-14 12:00:00"}, {"Open": 32248.0, "Close": 32190.39, "Max": 32498.99, "Min": 32100.0, "Volume": 32.7296336, "Date": "2020-01-14 12:30:00"}, {"Open": 32190.37, "Close": 32398.89, "Max": 32398.89, "Min": 32150.01, "Volume": 86.50232537, "Date": "2020-01-14 13:00:00"}, {"Open": 32398.99, "Close": 32495.38, "Max": 32497.11, "Min": 32283.0, "Volume": 10.48228624, "Date": "2020-01-14 13:30:00"}, {"Open": 32495.38, "Close": 32999.97, "Max": 33000.0, "Min": 32288.51, "Volume": 117.42275644, "Date": "2020-01-14 14:00:00"}, {"Open": 32999.96, "Close": 32900.01, "Max": 33199.98, "Min": 32699.04, "Volume": 100.97595796, "Date": "2020-01-14 14:30:00"}, {"Open": 32919.68, "Close": 33000.0, "Max": 33000.0, "Min": 32703.69, "Volume": 159.76691621, "Date": "2020-01-14 15:00:00"}, {"Open": 33000.0, "Close": 33046.18, "Max": 33079.97, "Min": 32852.9, "Volume": 118.72440166, "Date": "2020-01-14 15:30:00"}, {"Open": 32996.58, "Close": 32525.83, "Max": 33035.62, "Min": 32300.53, "Volume": 18.3070231, "Date": "2020-01-14 16:00:00"}, {"Open": 32524.99, "Close": 32673.77, "Max": 32939.38, "Min": 32360.0, "Volume": 93.17250567, "Date": "2020-01-14 16:30:00"}, {"Open": 32673.77, "Close": 33023.65, "Max": 33142.44, "Min": 32673.77, "Volume": 123.82239412, "Date": "2020-01-14 17:00:00"}, {"Open": 33041.99, "Close": 33249.98, "Max": 33398.99, "Min": 32850.02, "Volume": 50.71209703, "Date": "2020-01-14 17:30:00"}, {"Open": 33249.98, "Close": 33447.21, "Max": 33447.26, "Min": 33102.03, "Volume": 181.67455038, "Date": "2020-01-14 18:00:00"}, {"Open": 33438.31, "Close": 33212.49, "Max": 33450.0, "Min": 32900.01, "Volume": 5.34780429, "Date": "2020-01-14 18:30:00"}, {"Open": 33212.49, "Close": 33084.99, "Max": 33266.92, "Min": 32900.01, "Volume": 133.66388363, "Date": "2020-01-14 19:00:00"}, {"Open": 33069.99, "Close": 32921.05, "Max": 33090.0, "Min": 32900.03, "Volume": 68.13319656, "Date": "2020-01-14 19:30:00"}, {"Open": 33088.99, "Close": 33032.89, "Max": 33089.0, "Min": 32921.12, "Volume": 126.63226688, "Date": "2020-01-14 20:00:00"}, {"Open": 33032.89, "Close": 32947.95, "Max": 33060.0, "Min": 32700.12, "Volume": 14.21573713, "Date": "2020-01-14 20:30:00"}, {"Open": 32944.98, "Close": 32896.03, "Max": 32944.98, "Min": 32717.11, "Volume": 67.35503797, "Date": "2020-01-14 21:00:00"}, {"Open": 32896.03, "Close": 32940.58, "Max": 33050.0, "Min": 32896.02, "Volume": 46.68565275, "Date": "2020-01-14 21:30:00"}, {"Open": 32940.58, "Close": 33059.99, "Max": 33060.0, "Min": 32899.98, "Volume": 60.64368603, "Date": "2020-01-14 22:00:00"}, {"Open": 33058.99, "Close": 33059.98, "Max": 33060.0, "Min": 32998.99, "Volume": 13.78857534, "Date": "2020-01-14 22:30:00"}, {"Open": 33059.98, "Close": 33100.0, "Max": 33100.0, "Min": 32998.99, "Volume": 44.6759928, "Date": "2020-01-14 23:00:00"}, {"Open": 33128.2, "Close": 33304.52, "Max": 33520.0, "Min": 33030.02, "Volume": 226.59739768, "Date": "2020-01-14 23:30:00"}, {"Open": 33227.31, "Close": 33369.05, "Max": 33480.0, "Min": 32900.0, "Volume": 126.09650636, "Date": "2020-01-15 00:00:00"}, {"Open": 33479.99, "Close": 33106.76, "Max": 33479.99, "Min": 32900.01, "Volume": 150.26999975, "Date": "2020-01-15 00:30:00"}, {"Open": 33106.75, "Close": 32856.98, "Max": 33247.86, "Min": 32800.0, "Volume": 179.21401128, "Date": "2020-01-15 01:00:00"}, {"Open": 32868.36, "Close": 33081.61, "Max": 33157.33, "Min": 32800.06, "Volume": 124.37461203, "Date": "2020-01-15 01:30:00"}, {"Open": 33083.85, "Close": 33264.74, "Max": 33296.94, "Min": 32950.03, "Volume": 106.31521555, "Date": "2020-01-15 02:00:00"}, {"Open": 33264.2, "Close": 33239.39, "Max": 33264.2, "Min": 32960.0, "Volume": 47.61557527, "Date": "2020-01-15 02:30:00"}, {"Open": 33236.75, "Close": 33198.68, "Max": 33236.86, "Min": 33027.6, "Volume": 107.83399395, "Date": "2020-01-15 03:00:00"}, {"Open": 33164.63, "Close": 32999.09, "Max": 33198.06, "Min": 32810.01, "Volume": 45.05741621, "Date": "2020-01-15 03:30:00"}, {"Open": 32998.75, "Close": 32483.0, "Max": 32998.75, "Min": 32483.0, "Volume": 26.28861685, "Date": "2020-01-15 04:00:00"}, {"Open": 32480.01, "Close": 32599.74, "Max": 32715.25, "Min": 32450.0, "Volume": 123.74892433, "Date": "2020-01-15 04:30:00"}, {"Open": 32500.11, "Close": 32549.99, "Max": 32675.42, "Min": 32399.98, "Volume": 2.31334318, "Date": "2020-01-15 05:00:00"}, {"Open": 32400.01, "Close": 32270.0, "Max": 32550.0, "Min": 32267.02, "Volume": 14.76365909, "Date": "2020-01-15 05:30:00"}, {"Open": 32546.01, "Close": 32445.0, "Max": 32546.01, "Min": 32270.0, "Volume": 0.7646701, "Date": "2020-01-15 06:00:00"}, {"Open": 32445.0, "Close": 32620.01, "Max": 32621.89, "Min": 32310.01, "Volume": 7.48756148, "Date": "2020-01-15 06:30:00"}, {"Open": 32620.01, "Close": 32610.01, "Max": 32621.89, "Min": 32604.99, "Volume": 7.24294268, "Date": "2020-01-15 07:00:00"}, {"Open": 32610.01, "Close": 32449.99, "Max": 32610.01, "Min": 32348.0, "Volume": 74.58734283, "Date": "2020-01-15 07:30:00"}, {"Open": 32449.98, "Close": 32574.98, "Max": 32574.99, "Min": 32300.01, "Volume": 15.38745243, "Date": "2020-01-15 08:00:00"}, {"Open": 32574.98, "Close": 32562.95, "Max": 32574.99, "Min": 32400.01, "Volume": 51.72283559, "Date": "2020-01-15 08:30:00"}, {"Open": 32562.99, "Close": 32596.65, "Max": 32604.38, "Min": 32375.0, "Volume": 38.4271044, "Date": "2020-01-15 09:00:00"}, {"Open": 32596.62, "Close": 32999.7, "Max": 32999.88, "Min": 32375.01, "Volume": 6.27617116, "Date": "2020-01-15 09:30:00"}, {"Open": 32999.7, "Close": 32996.99, "Max": 33049.99, "Min": 32705.05, "Volume": 25.35192695, "Date": "2020-01-15 10:00:00"}, {"Open": 32996.99, "Close": 33187.97, "Max": 33187.99, "Min": 32900.0, "Volume": 44.95076789, "Date": "2020-01-15 10:30:00"}, {"Open": 33187.97, "Close": 33043.98, "Max": 33187.97, "Min": 32979.5, "Volume": 1.73455037, "Date": "2020-01-15 11:00:00"}, {"Open": 33043.98, "Close": 32998.07, "Max": 33043.98, "Min": 32900.0, "Volume": 7.79481189, "Date": "2020-01-15 11:30:00"}, {"Open": 32998.07, "Close": 32990.0, "Max": 32999.0, "Min": 32800.01, "Volume": 13.3931099, "Date": "2020-01-15 12:00:00"}, {"Open": 32990.0, "Close": 32966.52, "Max": 33000.0, "Min": 32862.66, "Volume": 154.10978063, "Date": "2020-01-15 12:30:00"}, {"Open": 32873.81, "Close": 33100.02, "Max": 33197.0, "Min": 32873.8, "Volume": 10.35398222, "Date": "2020-01-15 13:00:00"}, {"Open": 33100.02, "Close": 33399.99, "Max": 33399.99, "Min": 33100.0, "Volume": 23.40399744, "Date": "2020-01-15 13:30:00"}, {"Open": 33399.99, "Close": 33299.99, "Max": 33489.99, "Min": 33102.01, "Volume": 9.06890721, "Date": "2020-01-15 14:00:00"}, {"Open": 33299.99, "Close": 33399.81, "Max": 33489.97, "Min": 33143.93, "Volume": 94.30600321, "Date": "2020-01-15 14:30:00"}, {"Open": 33399.7, "Close": 33207.79, "Max": 33399.73, "Min": 32916.65, "Volume": 51.39760061, "Date": "2020-01-15 15:00:00"}, {"Open": 33207.78, "Close": 33083.95, "Max": 33207.84, "Min": 33001.0, "Volume": 61.55392306, "Date": "2020-01-15 15:30:00"}, {"Open": 33083.95, "Close": 33184.99, "Max": 33199.69, "Min": 32873.8, "Volume": 98.51673779, "Date": "2020-01-15 16:00:00"}, {"Open": 33184.99, "Close": 33138.02, "Max": 33224.68, "Min": 33007.66, "Volume": 1.80367129, "Date": "2020-01-15 16:30:00"}, {"Open": 33180.99, "Close": 32865.21, "Max": 33202.26, "Min": 32498.94, "Volume": 113.00296892, "Date": "2020-01-15 17:00:00"}, {"Open": 32938.4, "Close": 32989.98, "Max": 33118.35, "Min": 32666.03, "Volume": 2.7169386, "Date": "2020-01-15 17:30:00"}, {"Open": 32989.99, "Close": 32752.27, "Max": 32989.99, "Min": 32600.0, "Volume": 18.48685506, "Date": "2020-01-15 18:00:00"}, {"Open": 32754.53, "Close": 32800.0, "Max": 32989.99, "Min": 32700.0, "Volume": 46.87518283, "Date": "2020-01-15 18:30:00"}, {"Open": 32844.98, "Close": 32969.69, "Max": 32989.99, "Min": 32844.96, "Volume": 58.73300902, "Date": "2020-01-15 19:00:00"}, {"Open": 32969.68, "Close": 32900.0, "Max": 32969.69, "Min": 32860.0, "Volume": 1.13034249, "Date": "2020-01-15 19:30:00"}, {"Open": 32900.0, "Close": 32899.95, "Max": 32900.0, "Min": 32859.84, "Volume": 54.38986651, "Date": "2020-01-15 20:00:00"}, {"Open": 32899.95, "Close": 33129.65, "Max": 33149.98, "Min": 32859.84, "Volume": 2.43989605, "Date": "2020-01-15 20:30:00"}, {"Open": 33129.44, "Close": 33199.77, "Max": 33200.0, "Min": 32920.1, "Volume": 36.5356959, "Date": "2020-01-15 21:00:00"}, {"Open": 33199.77, "Close": 33189.03, "Max": 33199.79, "Min": 32920.06, "Volume": 54.57189256, "Date": "2020-01-15 21:30:00"}, {"Open": 33189.02, "Close": 33096.82, "Max": 33194.99, "Min": 32920.25, "Volume": 36.91199134, "Date": "2020-01-15 22:00:00"}, {"Open": 33096.82, "Close": 33200.0, "Max": 33200.0, "Min": 33000.04, "Volume": 12.9130503, "Date": "2020-01-15 22:30:00"}, {"Open": 33200.0, "Close": 33100.0, "Max": 33248.97, "Min": 33011.5, "Volume": 42.1483899, "Date": "2020-01-15 23:00:00"}, {"Open": 33100.0, "Close": 33174.55, "Max": 33199.99, "Min": 32816.01, "Volume": 27.37165618, "Date": "2020-01-15 23:30:00"}, {"Open": 33173.47, "Close": 32860.39, "Max": 33173.48, "Min": 32860.39, "Volume": 42.28545436, "Date": "2020-01-16 00:00:00"}, {"Open": 32899.72, "Close": 32831.37, "Max": 32899.72, "Min": 32821.0, "Volume": 19.92235291, "Date": "2020-01-16 00:30:00"}, {"Open": 32860.31, "Close": 32658.43, "Max": 32860.31, "Min": 32655.23, "Volume": 28.50873227, "Date": "2020-01-16 01:00:00"}, {"Open": 32657.9, "Close": 32617.77, "Max": 32657.9, "Min": 32557.45, "Volume": 37.9353543, "Date": "2020-01-16 01:30:00"}, {"Open": 32617.76, "Close": 32528.87, "Max": 32790.99, "Min": 32500.0, "Volume": 94.07071174, "Date": "2020-01-16 02:00:00"}, {"Open": 32544.32, "Close": 32774.04, "Max": 32797.09, "Min": 32543.45, "Volume": 14.46929114, "Date": "2020-01-16 02:30:00"}, {"Open": 32728.9, "Close": 32379.99, "Max": 32728.9, "Min": 32379.99, "Volume": 54.92036857, "Date": "2020-01-16 03:00:00"}, {"Open": 32446.63, "Close": 32641.71, "Max": 32661.23, "Min": 32446.63, "Volume": 36.59493989, "Date": "2020-01-16 03:30:00"}, {"Open": 32630.54, "Close": 32439.66, "Max": 32669.6, "Min": 32379.99, "Volume": 50.40146903, "Date": "2020-01-16 04:00:00"}, {"Open": 32380.6, "Close": 32592.74, "Max": 32730.02, "Min": 32380.6, "Volume": 35.58508568, "Date": "2020-01-16 04:30:00"}, {"Open": 32727.61, "Close": 32725.45, "Max": 32799.44, "Min": 32600.0, "Volume": 13.8962464, "Date": "2020-01-16 05:00:00"}, {"Open": 32725.66, "Close": 32728.6, "Max": 32743.2, "Min": 32725.47, "Volume": 39.56431596, "Date": "2020-01-16 05:30:00"}, {"Open": 32725.71, "Close": 32697.08, "Max": 32725.71, "Min": 32662.04, "Volume": 79.6013702, "Date": "2020-01-16 06:00:00"}, {"Open": 32696.6, "Close": 32697.14, "Max": 32702.33, "Min": 32692.31, "Volume": 15.82501996, "Date": "2020-01-16 06:30:00"}, {"Open": 32697.1, "Close": 32693.2, "Max": 32697.26, "Min": 32650.0, "Volume": 19.90067421, "Date": "2020-01-16 07:00:00"}, {"Open": 32693.21, "Close": 32693.27, "Max": 32693.49, "Min": 32550.0, "Volume": 102.13753371, "Date": "2020-01-16 07:30:00"}, {"Open": 32693.12, "Close": 32799.96, "Max": 32799.99, "Min": 32663.8, "Volume": 121.73385047, "Date": "2020-01-16 08:00:00"}, {"Open": 32799.01, "Close": 32730.23, "Max": 32799.99, "Min": 32697.56, "Volume": 79.52252482, "Date": "2020-01-16 08:30:00"}, {"Open": 32720.9, "Close": 32477.77, "Max": 32720.9, "Min": 32477.77, "Volume": 61.23897593, "Date": "2020-01-16 09:00:00"}, {"Open": 32598.22, "Close": 32543.36, "Max": 32710.47, "Min": 32400.0, "Volume": 45.48240204, "Date": "2020-01-16 09:30:00"}, {"Open": 32710.05, "Close": 32547.95, "Max": 32710.05, "Min": 32400.0, "Volume": 23.3366237, "Date": "2020-01-16 10:00:00"}, {"Open": 32548.49, "Close": 32597.97, "Max": 32597.97, "Min": 32400.02, "Volume": 6.95080988, "Date": "2020-01-16 10:30:00"}, {"Open": 32597.97, "Close": 32548.62, "Max": 32710.49, "Min": 32379.99, "Volume": 31.50441392, "Date": "2020-01-16 11:00:00"}, {"Open": 32488.16, "Close": 32859.62, "Max": 32859.62, "Min": 32488.16, "Volume": 36.76609492, "Date": "2020-01-16 11:30:00"}, {"Open": 32800.0, "Close": 33002.03, "Max": 33149.99, "Min": 32800.0, "Volume": 27.50983494, "Date": "2020-01-16 12:00:00"}, {"Open": 33055.28, "Close": 33002.49, "Max": 33055.28, "Min": 33000.0, "Volume": 2.98710087, "Date": "2020-01-16 12:30:00"}, {"Open": 32996.48, "Close": 32799.99, "Max": 32996.48, "Min": 32671.57, "Volume": 3.55505766, "Date": "2020-01-16 13:00:00"}, {"Open": 32799.73, "Close": 32859.88, "Max": 32894.72, "Min": 32697.04, "Volume": 3.66166867, "Date": "2020-01-16 13:30:00"}, {"Open": 32859.88, "Close": 32799.99, "Max": 32970.0, "Min": 32710.59, "Volume": 3.93591966, "Date": "2020-01-16 14:00:00"}, {"Open": 32799.99, "Close": 32862.62, "Max": 32888.88, "Min": 32725.19, "Volume": 2.81044341, "Date": "2020-01-16 14:30:00"}, {"Open": 32862.61, "Close": 32891.97, "Max": 32900.0, "Min": 32810.18, "Volume": 50.91440801, "Date": "2020-01-16 15:00:00"}, {"Open": 32891.99, "Close": 32960.0, "Max": 32960.0, "Min": 32847.0, "Volume": 29.3506365, "Date": "2020-01-16 15:30:00"}, {"Open": 32960.0, "Close": 32817.78, "Max": 32960.0, "Min": 32710.99, "Volume": 30.62638002, "Date": "2020-01-16 16:00:00"}, {"Open": 32817.78, "Close": 32718.0, "Max": 32817.79, "Min": 32629.01, "Volume": 154.81355475, "Date": "2020-01-16 16:30:00"}, {"Open": 32720.62, "Close": 32873.99, "Max": 32899.99, "Min": 32718.0, "Volume": 30.90286294, "Date": "2020-01-16 17:00:00"}, {"Open": 32873.98, "Close": 32897.77, "Max": 32940.0, "Min": 32800.5, "Volume": 36.4215039, "Date": "2020-01-16 17:30:00"}, {"Open": 32897.76, "Close": 32761.0, "Max": 32919.78, "Min": 32718.0, "Volume": 113.04749676, "Date": "2020-01-16 18:00:00"}, {"Open": 32761.0, "Close": 32910.84, "Max": 32948.99, "Min": 32750.77, "Volume": 7.26342964, "Date": "2020-01-16 18:30:00"}, {"Open": 32907.26, "Close": 32949.9, "Max": 32950.0, "Min": 32774.72, "Volume": 25.48256464, "Date": "2020-01-16 19:00:00"}, {"Open": 32949.9, "Close": 32940.0, "Max": 32949.9, "Min": 32830.79, "Volume": 54.36089746, "Date": "2020-01-16 19:30:00"}, {"Open": 32940.0, "Close": 32940.0, "Max": 32940.0, "Min": 32877.59, "Volume": 79.69695578, "Date": "2020-01-16 20:00:00"}, {"Open": 32940.0, "Close": 32999.91, "Max": 33000.0, "Min": 32889.99, "Volume": 5.02749006, "Date": "2020-01-16 20:30:00"}, {"Open": 32999.91, "Close": 32802.84, "Max": 33000.0, "Min": 32560.02, "Volume": 57.7807036, "Date": "2020-01-16 21:00:00"}, {"Open": 32802.84, "Close": 32865.26, "Max": 32912.6, "Min": 32675.37, "Volume": 14.6708684, "Date": "2020-01-16 21:30:00"}, {"Open": 32865.25, "Close": 32953.45, "Max": 32954.93, "Min": 32740.0, "Volume": 31.39911946, "Date": "2020-01-16 22:00:00"}, {"Open": 32953.15, "Close": 32966.31, "Max": 33000.0, "Min": 32899.99, "Volume": 30.96292165, "Date": "2020-01-16 22:30:00"}, {"Open": 32988.99, "Close": 32980.0, "Max": 33000.0, "Min": 32933.03, "Volume": 29.49776173, "Date": "2020-01-16 23:00:00"}, {"Open": 32956.02, "Close": 32999.99, "Max": 33000.0, "Min": 32865.44, "Volume": 25.09366486, "Date": "2020-01-16 23:30:00"}, {"Open": 32999.99, "Close": 32916.1, "Max": 32999.99, "Min": 32865.44, "Volume": 36.32628584, "Date": "2020-01-17 00:00:00"}, {"Open": 32915.68, "Close": 32910.13, "Max": 32999.86, "Min": 32823.98, "Volume": 10.38864531, "Date": "2020-01-17 00:30:00"}, {"Open": 32949.7, "Close": 32999.98, "Max": 32999.98, "Min": 32929.78, "Volume": 23.37683587, "Date": "2020-01-17 01:00:00"}, {"Open": 32975.02, "Close": 32989.91, "Max": 32999.94, "Min": 32907.62, "Volume": 25.85553698, "Date": "2020-01-17 01:30:00"}, {"Open": 32989.88, "Close": 32989.95, "Max": 32989.95, "Min": 32849.78, "Volume": 23.62502769, "Date": "2020-01-17 02:00:00"}, {"Open": 32957.88, "Close": 33021.22, "Max": 33021.22, "Min": 32957.88, "Volume": 21.27380451, "Date": "2020-01-17 02:30:00"}, {"Open": 33021.22, "Close": 33156.78, "Max": 33200.0, "Min": 33012.01, "Volume": 40.10323466, "Date": "2020-01-17 03:00:00"}, {"Open": 33156.82, "Close": 33138.14, "Max": 33199.98, "Min": 33125.72, "Volume": 75.79057766, "Date": "2020-01-17 03:30:00"}, {"Open": 33138.39, "Close": 33193.99, "Max": 33200.0, "Min": 33138.39, "Volume": 48.14799432, "Date": "2020-01-17 04:00:00"}, {"Open": 33197.99, "Close": 33137.72, "Max": 33197.99, "Min": 33052.7, "Volume": 16.48521889, "Date": "2020-01-17 04:30:00"}, {"Open": 33081.7, "Close": 33200.0, "Max": 33200.0, "Min": 33081.7, "Volume": 10.97878429, "Date": "2020-01-17 05:00:00"}, {"Open": 33200.0, "Close": 33250.0, "Max": 33250.0, "Min": 33170.02, "Volume": 9.34950924, "Date": "2020-01-17 05:30:00"}, {"Open": 33250.0, "Close": 33470.0, "Max": 33470.0, "Min": 33250.0, "Volume": 48.28228939, "Date": "2020-01-17 06:00:00"}, {"Open": 33470.0, "Close": 33469.99, "Max": 33470.0, "Min": 33395.01, "Volume": 58.07216839, "Date": "2020-01-17 06:30:00"}, {"Open": 33467.0, "Close": 33474.68, "Max": 33474.69, "Min": 33400.01, "Volume": 17.29952205, "Date": "2020-01-17 07:00:00"}, {"Open": 33450.0, "Close": 33500.0, "Max": 33500.0, "Min": 33449.01, "Volume": 3.20205393, "Date": "2020-01-17 07:30:00"}, {"Open": 33500.0, "Close": 33869.77, "Max": 33967.11, "Min": 33500.0, "Volume": 56.78192331, "Date": "2020-01-17 08:00:00"}, {"Open": 33900.0, "Close": 33720.0, "Max": 33906.46, "Min": 33640.0, "Volume": 41.19734451, "Date": "2020-01-17 08:30:00"}, {"Open": 33710.0, "Close": 33842.3, "Max": 34000.0, "Min": 33650.04, "Volume": 59.55008461, "Date": "2020-01-17 09:00:00"}, {"Open": 33842.3, "Close": 33970.18, "Max": 34000.0, "Min": 33800.0, "Volume": 63.11921925, "Date": "2020-01-17 09:30:00"}, {"Open": 33970.18, "Close": 33773.96, "Max": 34012.96, "Min": 33746.98, "Volume": 59.73699411, "Date": "2020-01-17 10:00:00"}, {"Open": 33819.99, "Close": 33898.98, "Max": 33972.63, "Min": 33714.0, "Volume": 37.71204274, "Date": "2020-01-17 10:30:00"}, {"Open": 33898.99, "Close": 33830.01, "Max": 34000.0, "Min": 33821.16, "Volume": 40.44026402, "Date": "2020-01-17 11:00:00"}, {"Open": 33987.99, "Close": 33859.44, "Max": 33987.99, "Min": 33800.0, "Volume": 22.16286876, "Date": "2020-01-17 11:30:00"}, {"Open": 33859.44, "Close": 33500.0, "Max": 33874.12, "Min": 33480.0, "Volume": 10.98567418, "Date": "2020-01-17 12:00:00"}, {"Open": 33500.0, "Close": 33555.0, "Max": 33718.71, "Min": 33500.0, "Volume": 3.77999493, "Date": "2020-01-17 12:30:00"}, {"Open": 33551.04, "Close": 33673.51, "Max": 33673.51, "Min": 33500.0, "Volume": 49.98764188, "Date": "2020-01-17 13:00:00"}, {"Open": 33673.51, "Close": 33701.73, "Max": 33729.07, "Min": 33558.59, "Volume": 54.59719818, "Date": "2020-01-17 13:30:00"}, {"Open": 33701.73, "Close": 33523.25, "Max": 33714.63, "Min": 33462.4, "Volume": 52.81971837, "Date": "2020-01-17 14:00:00"}, {"Open": 33501.0, "Close": 33498.65, "Max": 33626.35, "Min": 33400.0, "Volume": 32.76818469, "Date": "2020-01-17 14:30:00"}, {"Open": 33498.65, "Close": 33588.0, "Max": 33627.24, "Min": 33400.01, "Volume": 94.98696135, "Date": "2020-01-17 15:00:00"}, {"Open": 33588.0, "Close": 33722.0, "Max": 33794.59, "Min": 33552.87, "Volume": 6.55049184, "Date": "2020-01-17 15:30:00"}, {"Open": 33722.0, "Close": 33917.79, "Max": 33946.0, "Min": 33722.0, "Volume": 148.18762042, "Date": "2020-01-17 16:00:00"}, {"Open": 33917.79, "Close": 33860.96, "Max": 34000.0, "Min": 33860.96, "Volume": 8.43825364, "Date": "2020-01-17 16:30:00"}, {"Open": 33915.98, "Close": 33950.05, "Max": 34058.39, "Min": 33771.03, "Volume": 69.02091738, "Date": "2020-01-17 17:00:00"}, {"Open": 33950.05, "Close": 33989.96, "Max": 34045.18, "Min": 33888.91, "Volume": 86.21982364, "Date": "2020-01-17 17:30:00"}, {"Open": 33989.96, "Close": 34045.42, "Max": 34045.42, "Min": 33943.96, "Volume": 0.56891675, "Date": "2020-01-17 18:00:00"}], "candlesCount": 199, "graphMin": 30683.93, "graphMax": 34058.39}