import os
import csv
import cv2
import uuid
import time
import numpy as np
import pandas as pd
import pickle
import subprocess
from time import sleep
import modules.config as cf

class PriceHandler:
    # We need prices for our predicted products, so this class can be used for generating csv file...
    # ...which contains information about name and price
    # Price data can be later read / manipulated with functions
    def __init__(self, path, classnames, header=["name", "price_kg"]):
        self.path = path
        self.header = header
        self.classNames = classnames
        self.checkForPriceList()
    def printClassnames(self):
        print(self.classNames)

    def updateClassnames(self, classnames):
        self.classNames = classnames

    def checkForPriceList(self):
        if not os.path.exists(self.path):
            self.initialisePriceList()

    # Creates/overrides existing price file with classnames and price set to zero...
    # ... User is asked for confirmation if file exists
    def initialisePriceList(self):
        if os.path.exists(self.path):
            if not input("Price file already exists, override all data? Y/N") == "Y":
                print("Quitting...")
                return
            else:
                print("Overriding the data...")

        with open (self.path, 'w', newline='') as csvfile:
            pricewriter = csv.writer(csvfile, delimiter=',')
            pricewriter.writerow(self.header)
            for item in self.classNames:
                pricewriter.writerow([item, 0])

    # Change items price
    def changePrice(self, classname, newPrice):
        df = pd.read_csv(self.path)
        df.loc[df['name']==classname, "price_kg"] = newPrice
        df.to_csv(self.path, index=False)

    # Prints all items and prices
    def printPrices(self):
        if not os.path.exists(self.path):
            print("File doesn't exist yet, initialise first")
        else:
            print("Printing prices\n")
            with open(self.path, newline='') as csvfile:
                reader = csv.DictReader(csvfile)
                print('Name Price')
                for row in reader:
                    print(row['name'] + ' ' + row['price_kg'])

    # For every item user is asked to give price
    def setPrices(self):
        print("Asking prices")
        df = pd.read_csv(self.path)
        for name in df['name']:
            price = input('Give price for ' + name + ': ')
            df.loc[df['name']==name, "price_kg"] = price
        df.to_csv(self.path, index=False)

    # Return price for classname
    def returnPrice(self, classname):
        df = pd.read_csv(self.path)
        try:
            price = df.loc[df["name"]==classname, "price_kg"].values[0]
            #print(price)
            return price
        except:
            print("Item doesn't exist")

    def menu(self):
        continueProgram = True

        while(continueProgram):
            selection = input("\nPRICE MENU\n1. View items and prices \n2. Set prices for every item\n3. Change item price\n4. Get item price\n5. Reset (initialize)\n6. Go back to main menu")
            if selection == '1':
                self.printPrices()
            elif selection == '2':
                if input("You really want to set prices for every item? Y/N") == "Y":
                    self.setPrices()
            elif selection == '3':
                self.printPrices()
                item = input("Which items price you want to change? ")
                price = input("Give a new price ")
                self.changePrice(item, price)
            elif selection == '4':
                 item = input("Which items price you want to get? ")
                 print(self.returnPrice(item))
            elif selection == '5':
                self.initialisePriceList()
            elif selection == '6':
                # Returning so user is not asked to press key to continue
                continueProgram = False
                return
            else:
                print("Wrong input")
            input('Press enter key to continue')

class PictureTaker:
    # Takes single picture which can be then used in PicturePredicter class
    # Crops the image and resizes to 128 and then saves to path given in constructor
    # Path is same for all so overwriting is inevitable, unless uuid() or so is added

    # Add imagefolder_path and ?
    def __init__(self, picture_path):
        self.picture_path = picture_path
        self.picture_size = cf.picture_size
        self.cv2_cam = cf.cv2_cam
        #self.cap = cv2.VideoCapture(cv2_cam, cv2.CAP_DSHOW)
        #self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
        #self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 280)

    def takePicture(self):
        if os.name == 'nt':
            self.cap = cv2.VideoCapture(self.cv2_cam, cv2.CAP_DSHOW)
        else:
            self.cap = cv2.VideoCapture(self.cv2_cam)

        pictureTaken = False
        counter = 0
        while(not pictureTaken):
            ret, frame = self.cap.read()
            counter+=1
            if counter == 10:
                frame = self.crop_square(frame, self.picture_size, cv2.INTER_AREA)
                cv2.imwrite(self.picture_path, frame)
                self.cap.release()
                pictureTaken = True

    def displayAndTakePicture(self, destroy=True):
        # Displays videoimage and takes picture on ESC press (enter for rasp)
        print("\nDisplaying camera, press ESC on cmd to close")
        if os.name == "nt":
            self.cap = cv2.VideoCapture(self.cv2_cam, cv2.CAP_DSHOW)
        else:
            self.cap = cv2.VideoCapture(self.cv2_cam)
        while(self.cap.isOpened()):
            ret, frame = self.cap.read()
            if ret == True:
                cv2.imshow('frame', frame)
                if self.checkForKeyPress():
                    frame = self.crop_square(frame, self.picture_size, cv2.INTER_AREA)
                    cv2.imwrite(self.picture_path, frame)
                    break
                cv2.waitKey(25)
            else:
                break
                #ret, frame = self.cap.read()

        self.cap.release()
        if destroy == True:
            cv2.destroyAllWindows()

    def displayPicture(self, destroy=True):
        # Displays videoimega until ESC is pressed
        print("\nDisplaying camera, press ESC on cmd to close")
        if os.name == "nt":
            self.cap = cv2.VideoCapture(self.cv2_cam, cv2.CAP_DSHOW)
        else:
            self.cap = cv2.VideoCapture(self.cv2_cam)
        while(self.cap.isOpened()):
            ret, frame = self.cap.read()
            if ret == True:
                cv2.imshow('frame', frame)
                if self.checkForKeyPress():
                    break
                cv2.waitKey(25)
            else:
                break

        self.cap.release()
        if destroy == True:
            cv2.destroyAllWindows()

    def heardEnter(self):
        import select
        import sys
        i,o,e = select.select([sys.stdin],[],[],0.0001)
        for s in i:
            if s == sys.stdin:
                input = sys.stdin.readline()
                return True
        return False

    def checkForKeyPress(self):
        # Returns true if esc (win) or enter (rasp) is pressed
        if os.name == 'nt':
            import msvcrt
            if msvcrt.kbhit():
                if ord(msvcrt.getch()) == 27:
                    return True
        else:
            import sys
            import select
            i,o,e = select.select([sys.stdin],[],[],0.0001)
            for s in i:
                if s == sys.stdin:
                    input = sys.stdin.readline()
                    return True
        return False

    def crop_square(self, img, size, interpolation):
        h, w = img.shape[:2]
        min_size = np.amin([h,w])

        # Centralize and crop
        crop_img = img[int(h/2-min_size/2):int(h/2+min_size/2), int(w/2-min_size/2):int(w/2+min_size/2)]
        resized = cv2.resize(crop_img, (size, size), interpolation=interpolation)

        return resized

class PictureTakerWithClass(PictureTaker):
    # Before model is trained we must be able to take pictures to a folder named after a classname
    # This is a child class that inherits PictureTaker, and both are constructed with folder path
    # Before taking picture, parent classes picture_path is changed by address randomiser which ...
    # combines imagefolder_path and random address with .jpg extension

    def __init__(self, root_image_path, imagefolder_path, testimagefolder_path, no_model=True):
        PictureTaker.__init__(self,imagefolder_path)
        self.imagefolder_root_path = root_image_path
        self.testimagefolder_path = testimagefolder_path
        # root path remembers, class path mutates
        self.imagefolder_root_class_path = imagefolder_path
        self.imagefolder_class_path = imagefolder_path
        self.no_model = no_model
        if not os.path.exists(root_image_path):
            os.makedirs(root_image_path)

        if not os.path.exists(self.imagefolder_root_class_path):
            self.initialisePictures()

    def randomisePictureDestinationAddress(self, root_path):
        #image_path = os.path.join(self.imagefolder_class_path, str(uuid.uuid1()) + '.jpg')
        image_path = os.path.join(root_path, str(uuid.uuid1()) + '.jpg')
        self.picture_path = image_path

    def printPaths(self):
        print("Imagefolder root path: " + self.imagefolder_root_path)
        print("Imagefolder root class path: " + self.imagefolder_root_class_path)
        print("Imagefolder class path:" + self.imagefolder_class_path)

    def takePictureRandomAddress(self, path):
        self.randomisePictureDestinationAddress(path)
        self.displayAndTakePicture(False)
        #self.takePicture()

    def askUserAndTakePicturesWithClass(self):
        classname = input('For which class you want to take pictures ')
        amount = input('How many pictures you want to take ')
        self.takePicturesWithClass(classname, amount)

    def initialisePictures(self):
    # Training pictures and test pictures are located in separate folders
    # Training pictures are taken first
    # Makes sure that picture to be predicted has folder to be saved to
        if not os.path.exists(self.imagefolder_root_class_path):
            print("Path for pictures was not found, if you don't have trained model, you should take pictures")
            if input ('Take pictures or continue without? Y/N ') == 'Y':
                #os.makedirs(self.imagefolder_root_path)
                mode_train = True
            else:
                return
            while(mode_train):
                self.askUserAndTakePicturesWithClass()
                if input('Continue taking pictures? Y/N ') != 'Y':
                    mode_train = False

            while(not mode_train):
                print('Taking testing pictures... ')
                classname = input("For which class you want to take testing pictures? ")
                amount = input("How many testing pictures you want to take? ")
                self.takeTrainingPicturesWithClass(classname, amount)

                if input('Continue taking training pictures? Y/N ') == 'N':
                    return

    def takePicturesWithClass(self, classname, amount):
        self.imagefolder_class_path = os.path.join(self.imagefolder_root_class_path, classname)
        if not os.path.exists(self.imagefolder_class_path):
            os.makedirs(self.imagefolder_class_path)
        print('\nTaking pictures for class: ' + classname + '\nFolder: ' + self.imagefolder_class_path)
        for i in range(int(amount)):
            #self.displayPicture(False)
            print("taking picture number " + str(i+1))
            self.takePictureRandomAddress(self.imagefolder_class_path)
            if i == int(amount) - 1:
                cv2.destroyAllWindows()

    def printInfoAboutImages(self):
        # Prints console how many pictures each imagefolder have
        try:
            directories = os.listdir(self.imagefolder_root_class_path)
        except:
            print("Classpictures weren't found")
            return
        file_counts = []
        for index, item in enumerate(directories):
            file_counts.append({'classname': item, 'count': len(os.listdir(os.path.join(self.imagefolder_root_class_path, item)))})

        try:
            training_directories = os.listdir(self.testimagefolder_path)
        except:
            print("Testing pictures weren't found")
            return

        training_file_counts = []
        for index, item in enumerate(training_directories):
            training_file_counts.append({'classname': item, 'count': len(os.listdir(os.path.join(self.testimagefolder_path, item)))})

        print("\nClassname Count:\n")
        for item in file_counts:
            print(str(item.get('classname')) + " " + str(item.get('count')))

        print("\nTraining class count:\n")
        for item in training_file_counts:
            print(str(item.get('classname')) + " " + str(item.get('count')))
        # Print image counts and are counts even

    def takeTrainingPicturesWithClass(self, classname, amount):
            self.imagefolder_class_path = os.path.join(self.testimagefolder_path, classname)
            if not os.path.exists(self.imagefolder_class_path):
                os.makedirs(self.imagefolder_class_path)
            print('\nTaking pictures for class: ' + classname + '\nFolder: ' + self.testimagefolder_path)
            for i in range(int(amount)):
                #self.displayPicture(False)
                print("taking picture number " + str(i+1))
                self.takePictureRandomAddress(self.imagefolder_class_path)
                if i == int(amount) - 1:
                    cv2.destroyAllWindows()

    def movePictures():
        # Maybe images need to be moved
        pass
    def printinfo():
        # Print info like classnames, file counts, are folders missing pictures etc..
        pass

    def menu(self):
        continueProgram = True

        while(continueProgram):
            selection = input("\nTRAINING MENU\n1. Take pictures with class\n2. Take testing pictures \n3. Get current paths\n4. Print info\n5. Go back to main menu")
            if selection == '1':
                classname = input("For which class you want to take pictures? ")
                amount = input("How many pictures you want to take? ")
                self.takePicturesWithClass(classname, amount)
            elif selection == '2':
                classname = input("For which class you want to take testing pictures? ")
                amount = input("How many testing pictures you want to take? ")
                self.takeTrainingPicturesWithClass(classname, amount)
            elif selection == '3':
                self.printPaths()
            elif selection == '4':
                self.printInfoAboutImages()
            elif selection == '5':
                continueProgram = False
                if self.no_model:
                    exit()
                return

            elif selection == 'train':
                if input("Retrain model? (requires restart) Y/N") == 'Y':
                    subprocess.call("python trainmodel.py", shell=True)
                    input("Model was retrained, exit with enter...")
                    exit()
            else:
                print("Wrong input")
            input('Press enter key to continue')

class Numpad:
    def waitForUserInput(self):
        return input("Up or down U/D")

class LcdHandler():
    #Inherits CharLCD, probably needs to be used in own program to avoid collisions with windows system
    #def __init__(self):
    #    CharLCD.__init__(self, pin_rs=15, pin_rw=18, pin_e=16, pins_data=[21,22,23,24],
    #            numbering_mode=GPIO.board)

    def printInfo(self, info):
        print("LCD HANDLER " + info + " LCD HANDLER")

    def writeString(self, string):
        #self.write_string(string)
        #sleep(2)
        #self.clear()
        print(string)

    def stop(self):
        self.clear()
        GPIO.cleanup()

class Menu(Numpad, LcdHandler):
    # Protyping menu system for 16*2 lcd screen with keypad
    # Construct different menus, keep hold of current,
    # return state, move to next, move to previous etc..
    # Inherits Numpad which asks for user input
    def __init__(self, menuItems):
        self.menuItems = menuItems
        self.menuItems.append('Exit')
        self.currentState = State(0, menuItems[0])

    def printMenuItems(self):
        for item in self.menuItems:
            print(item)

    def printCurrentState(self):
        print("Item: " + self.currentState.item + " index: " + str(self.currentState.index))

    def getCurrentState(self):
        return self.currentState

    def moveToPreviousState(self):
        if self.currentState.index == 0:
            self.currentState.index = len(self.menuItems)-1
            self.currentState.item = self.menuItems[self.currentState.index]
        #elif self.currentState.index == len(self.menuItems):
        #    self.currentState.index = len(self.menuItems)-1
        #    self.currentState.item = self.menuItems[self.currentState.index]
        else:
            self.currentState.index = self.currentState.index - 1
            self.currentState.item = self.menuItems[self.currentState.index]

    def moveToNextState(self):
        if self.currentState.index == len(self.menuItems) -1:
            self.currentState.index = 0
            self.currentState.item = self.menuItems[self.currentState.index]
        #elif self.currentState.index == len(self.menuItems):
        #    return
        else:
            self.currentState.index = self.currentState.index + 1
            self.currentState.item = self.menuItems[self.currentState.index]

    def moveUpOrDown(self, direction):
        if direction == 'U':
            self.moveToNextState()
        elif direction == 'D':
            self.moveToPreviousState()

    def display(self):
        # This will eventually display row on lcd screeen
        self.currentState.index = 0
        self.currentState.item = self.menuItems[self.currentState.index]
        self.printCurrentState()
        selection = self.waitForUserInput()
        while (selection != 'E'):
            self.moveUpOrDown(selection)
            self.printCurrentState()
            self.printInfo(self.getCurrentState().item)
            selection = self.waitForUserInput()
        print('Leaving menu with index ' + str(self.getCurrentState().index))
        return self.getCurrentState().index

    def displayLcd(self):
        self.currentState.index = 0
        self.currentState.item = self.menuItems[self.currentState.index]
        self.printCurrentState()
        selection = self.waitForUserInput()
        while (selection != 'E'):
            self.moveUpOrDown(selection)
            self.printCurrentState()
            self.printInfo(self.getCurrentState().item)
            selection = self.waitForUserInput()
        print('Leaving menu with index ' + str(self.getCurrentState().index))
        return self.getCurrentState().index

class State:
    def __init__(self, index, menuItem):
        self.index = index
        self.item = menuItem

class Datasaver:
    def __init__(self, path, header=['Date', 'Product','Weight','PricePerKilo','TotalPrice']):
        self.path=path
        self.header=header
        self.checkForExisting()

    def checkForExisting(self):
        if not os.path.isfile(self.path):
            with open (self.path, 'w', newline='') as csvfile:
                pricewriter = csv.writer(csvfile, delimiter=',')
                pricewriter.writerow(self.header)
        else:
            print("file exists")
            #pass

    def saveData(self,product,priceperkilo,weight):
        from datetime import date
        today = date.today()
        weightInKg = weight/1000
        totalprice = round(priceperkilo * weightInKg, 2)
        #print('The TotalPrice is: ',totalprice)
        #print("Today's date is :", today)

        arrayOfItems=[str(today), str(product), str(weightInKg), str(priceperkilo), str(totalprice)]
        with open(self.path, 'a', newline='') as f:
          writer = csv.writer(f, delimiter=',')
          writer.writerow(arrayOfItems)

if __name__ == "__main__":
    main()


import pytest
import os
import boto3
import botocore
from tempfile import NamedTemporaryFile
from cloud_data_connector.aws.connector import Connector
from cloud_data_connector.aws.downloader import Downloader
from cloud_data_connector.aws.uploader import Uploader

def test_connect(aws_credentials):
    # testing the Connector class and create a s3_client
    connector = Connector()
    s3_client = connector.connect()
    assert isinstance(s3_client, botocore.client.BaseClient), "S3 client is not created"

def test_connect_with_connection_string(aws_credentials):
    # testing the Connector class and create a s3_client
    """Check TypeError raised when passed a connection string"""
    with pytest.raises(TypeError):
        connector = Connector()
        resource = boto3.resource('s3')
        connector.connect(connection_string="conection_string")

def test_connect_error(aws_credentials):
    """Check TypeError raised when passed an object not compatible"""
    with pytest.raises(TypeError):
        connector = Connector()
        resource = boto3.resource('s3')
        connector.connect(connector_object=resource)

def test_list_blobs(aws_session, s3_test):
    bucket_name = 'my-test-bucket'
    file_text = "test"
    with NamedTemporaryFile(delete=True, suffix=".csv") as tmp:
        with open(tmp.name, "w", encoding="UTF-8") as f:
            f.write(file_text)
        # create a connector using a aws session
        connector = Connector()
        connection_obj = connector.connect()
        # create an Uploader using a connector object
        uploader = Uploader(connection_obj)
        # upload two files for testing
        uploader.upload(bucket_name, tmp.name, "file1.csv")
        uploader.upload(bucket_name, tmp.name, "file2.csv")

        # create a Downloader object to list object/files from a bucket
        downloader = Downloader(connection_obj)
        actual = downloader.list_blobs(bucket_name)
        assert actual == ["file1.csv","file2.csv"], "Files listed incorrectly!"

def test_download(aws_session, s3_test):
    bucket_name = 'my-test-bucket'
    file_text = "test"
    with NamedTemporaryFile(delete=True, suffix=".csv") as tmp:
        with open(tmp.name, "w", encoding="UTF-8") as f:
            f.write(file_text)
        # testing the Downloader class and download a file
        connector = Connector()
        connector_obj = connector.connect()
        # create an Uploader and a file for testing
        uploader = Uploader(connector_obj)
        uploader.upload(bucket_name, tmp.name, "file3.csv")
        # download file named file3.csv for testing
        downloader = Downloader(connector_obj)
        # download file from bucket and name it example.csv
        downloader.download(bucket_name, "file3.csv", "example.csv")
        # check if file was downloaded and exist in our local dir
        assert os.path.isfile('example.csv'), "File not downloaded"
        # delete files downloaded
        os.remove("example.csv")

def test_upload(aws_session, s3_test):
    bucket_name = 'my-test-bucket'
    file_text = "test_upload"
    with NamedTemporaryFile(delete=True, suffix=".csv") as tmp:
        with open(tmp.name, "w", encoding="UTF-8") as f:
            f.write(file_text)
        # create a Downloader object using a connector object
        connector = Connector()
        connector_obj = connector.connect()
        uploader = Uploader(connector_obj)
        # upload a file to bucket
        uploader.upload(bucket_name, tmp.name, "file4.csv")
        # list all files from bucket and check if uploaded file exists
        downloader = Downloader(connector_obj)
        list_blobs = downloader.list_blobs(bucket_name)
        assert list_blobs == ["file4.csv"]

if __name__=='__main__':
    pytest.main()


# -*- coding: utf-8 -*-
"""
Created on Wed Apr  7 13:06:09 2021

@author: 片山雅利(softcreate)
"""

def createFib():
    beforeFib = 1
    fib = 1
    for i in range(10000):
        nowFib = beforeFib + fib
        if len(str(nowFib)) == 1000:
            print(i + 3)
            print(nowFib)
            exit(0)
        beforeFib = fib
        fib = nowFib

if __name__ == '__main__':
    createFib()


#! /usr/bin/python

import serial
import os
from time import sleep, time
import threading
from pyrow import pyrow
from pyrow.pyrow import PyErg
import json
import numpy as np
from VideoControl import VideoControl
import os
run_thread = True

all_data = list()

cnt_rot = 0
cnt_trans = 0
cnt_erg = 0
cnt_image = 0

do_beep = False

vc = VideoControl()

# seq_name = input("name for sequence: ")
# print(seq_name)

#
# t = int(time())
# run_name = "%s_%i" % (seq_name, t)
# folder = '/tmp/%s/' % run_name
# os.mkdir(folder)

min_gripper = 0
current_gripper = 0
gripper_front_pos = 0

def RotationThread():
    global cnt_rot, current_gripper, min_gripper, gripper_front_pos
    name = '/dev/serial/by-id/usb-SEGGER_J-Link_000599005480-if00'
    ser = serial.Serial(name, baudrate=115200)
    print(ser.is_open)

    rots = list()

    while run_thread:
        data = ser.readline().strip()
        if data:
            s = str(data)[2:][:-1]
            # print(s)
            spl = s.split(':')
            if len(spl) != 3:
                print("Could not parse " + s)
                continue

            try:
                speed, angle, rotations = map(float, spl)
            except ValueError as e:
                print(e)
                continue

            if angle < 0:
                angle += 360

            rot = angle + rotations*360

            rot_m = rot*0.00246219 * 100
            cnt_rot += 1
            if cnt_rot % 10 != 0:
                continue
                print("%.2f" % (rot_m))
            # continue

            current_gripper = rot_m
            rots.append(rot_m)

            if len(rots) < 5:
                continue

            a = rots[-3]
            b = rots[-2]
            c = rots[-1]

            # print("%.2f, %.2f, %.2f" % (a, b, c))

            if a < b and b > c and abs(a-b) > 0.04:
                print ("XXXXXXXXXXXX MAXIMUM DETECTED at %i" % int(time()))
                # print("%.2f < %.2f > %.2f" % (a, b, c))
                min_gripper = c
                if do_beep:
                    os.system("beep -f 1000 -l 50")

            if a > b and b < c and abs(a - b) > 0.04:
                print("000000000000000000 Minimum at %i: %.1f" % (int(time()), c))
                # print("%.2f < %.2f > %.2f" % (a, b, c))
                gripper_front_pos = c
                if do_beep:
                    os.system("beep -f 1000 -l 50")

            # print(a, b, c)

    ser.close()

def TranslationThread():
    global cnt_trans, current_gripper, min_gripper
    name = '/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0'
    ser = serial.Serial(name, baudrate=230400)

    back = False

    all_trans = list()
    last_stamp = None
    stop_pos = 0
    stop_stamp = None

    front_stop = False
    front_stop_pos = 0
    front_stop_stamp = 0

    while run_thread:
        data = ser.readline()
        cnt_trans += 1
        if data:
            s = str(data)[2:][:-5]
            try:
                trans = float(s)
            except ValueError:
                continue

            trans = 0.03*trans/10 + 20
            if cnt_trans % 20 != 0:
                continue

            # print(trans)

            all_trans.append(trans)

            if len(all_trans) < 5:
                continue

            a = all_trans[-3]
            b = all_trans[-2]
            c = all_trans[-1]

            # print("%.2f, %.2f, %.2f" % (a, b, c))
            # print(c)
            v = c-b
            if c < 50:
                if back: # already stooped, waiting for acceleration:
                    # print("back: v: %.1f" % v)
                    if c > stop_pos + 5:  #v > 0.1:
                        dt_ms = (time()-stop_stamp)*1000.0
                        print("Moving FORWARD AGAIN after %.0f ms" % dt_ms)

                        gripper_dist = min_gripper - current_gripper
                        print("Gripper moved: %.1f (min: %.1f, current: %.1f" % (gripper_dist, min_gripper, current_gripper))
                        if min_gripper > 0 and gripper_dist < 500:
                            # os.system("beep -f 20 -l 300")
                            vc._say("Arms away")
                            # os.system("beep -f 200 -l 100")
                            # os.system("beep -f 100 -l 100")
                        if do_beep:
                            os.system("beep -f 900 -l 100")
                        back = False
                else:
                    # Not yet stopped:
                    # print("front yet? %.2f" % v)
                    # print()
                    if 0 > v > -0.5:
                        print("XXXXXXXXXXXXXXXXXXx BACKWARDS, STOPPING")
                        if do_beep:
                            os.system("beep -f 600 -l 100")
                        stop_pos = c
                        stop_stamp = time()
                        back = True

            # shooting the slide:
            if front_stop_pos > 0:
                # we are on the way back:
                if front_stop_pos - c > 20:
                    gripper_travel = (current_gripper - gripper_front_pos)/10.0  # to cm
                    print("00000000000000000000000000000000000000000000000000 Grpper travel: %i" % (int(gripper_travel)))
                    front_stop_pos = 0
                    if gripper_travel < 12:
                        vc._say("slide!")

            if c > 50:
                # print(v)

                if not front_stop:
                    if 0 < v < 1.0:
                        print("Front Stop")
                        front_stop = True
                        front_stop_pos = c
                        front_stop_stamp = time()
                        if do_beep:
                            os.system("beep -f 200 -l 100")
                else:
                    # we stopped, waiting for moving back:
                    if c < front_stop_pos - 3:
                        dt = (time()-front_stop_stamp)*1000.0
                        print("Moving back after %.1f ms" % dt)
                        front_stop = False
                        if do_beep:
                            os.system("beep -f 700 -l 100")

                #     if last_stamp and time()-last_stamp < 0.6:
                #         print("DT", time()-last_stamp)
                #         continue
                #
                #     print("Auslage")
                #     last_stamp = time()
                #     os.system("beep -f 200 -l 200")

            # print("%.1f" % (c-b))
            # if a < b and b > c and abs(a-b) > 0.04:
            #     print ("XXXXXXXXXXXX MAXIMUM DETECTED at %i" % int(time()))
            #     print("%.2f < %.2f > %.2f" % (a, b, c))
            #     os.system("beep -f 200 -l 200")
            #
            # if a > b and b < c and abs(a - b) > 0.04:
            #     print("000000000000000000 at %i" % int(time()))
            #     print("%.2f < %.2f > %.2f" % (a, b, c))
            #     os.system("beep -f 700 -l 200")

            # now = time()
            # msg = "T, %f, %.0f" % (now, trans)
            # all_data.append([now, msg])
            cnt_trans +=1

def ErgThread():
    global cnt_erg
    ergs = list(pyrow.find())

    erg = PyErg(ergs[0])

    while run_thread:
        erg_dict = erg.get_monitor(forceplot=True)
        now = time()
        msg = "E, %f, %s" % (now, json.dumps(erg_dict))
        all_data.append([now, msg])
        cnt_erg += 1

def CameraThread():
    global cnt_image
    cap = cv2.VideoCapture(1)
    while run_thread:
        # Capture frame-by-frame
        ret, frame = cap.read()
        t = time()
        img_path = folder + 'img_%f.png' % t
        cnt_image += 1

        cv2.imwrite(img_path, frame)

threads = list()
threads.append(threading.Thread(target=RotationThread, daemon=True))
threads.append(threading.Thread(target=TranslationThread, daemon=True))
# threads.append(threading.Thread(target=ErgThread, daemon=True))
# threads.append(threading.Thread(target=CameraThread, daemon=True))
#
for t in threads:
    t.start()
#
while True:
    sleep(40)
run_thread = False
#
# print("Rot: %i, Trans: %i, Erg: %i, Images: %i" % (cnt_rot, cnt_trans, cnt_erg, cnt_image))
#
# all_data = sorted(all_data, key=lambda d: d[0])
#
#
#
# print("Writing to %s" % folder)
#
# f_r = open(folder + 'rotation.txt', 'w')
# f_t = open(folder + 'translation.txt' , 'w')
# f_e = open(folder + 'ergo.txt', 'w')
#
# f_merge = open(folder + 'all_%s.txt' % run_name, 'w')
#
# for m in all_data:
#     msg = m[1]
#     f_merge.write(msg+'\n')
#     if msg[0] == 'R':
#         f_r.write(msg+'\n')
#     if msg[0] == 'T':
#         f_t.write(msg + '\n')
#     if msg[0] == 'E':
#         f_e.write(msg + '\n')
#     f_merge.write(msg+'\n')
#
# f_r.close()
# f_t.close()
# f_e.close()


import pickle
class Animal:
    def __init__(self, name, hp, atk):
        self.name = name
        self.hp = hp
        self.atk = atk

class Person(Animal):
    def __init__(self, name, hp, atk, sex):
        super().__init__(name, hp, atk)
        self.sex = sex
    # 重写一下内置的双下str，让实例能被print打印出属性
    def __str__(self):
        return str(self.__dict__)

class Dog(Animal):
    def __init__(self, name, hp, atk, kind):
        super().__init__(name, hp, atk)
        self.kind = kind

hero = Person('铁乐', 100, 10, '男')
print(hero)
# 重写双下str后打印出{'sex': '男', 'name': '铁乐', 'atk': 10, 'hp': 100}

# 对象也可以被pickle序列化，这是在内存中操作的示例
ret = pickle.dumps(hero)
print(ret)
# 显示bytes类型的字节：
# b'\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x03\x00\x00\x00atkq\x03K\nX\x04\x00\x00\x00nameq\x04X\x06\x00\x00\x00\xe9\x93\x81\xe4\xb9\x90q\x05X\x03\x00\x00\x00sexq\x06X\x03\x00\x00\x00\xe7\x94\xb7q\x07X\x02\x00\x00\x00hpq\x08Kdub.'
res = pickle.loads(ret)
print(type(res), res)
# 重新输出成 <class '__main__.Person'> {'hp': 100, 'atk': 10, 'name': '铁乐', 'sex': '男'}


# -*- coding: utf-8 -*-
from app.api.db.session import SessionLocal
from app.api.logger import logger

class Database(object):

    def __init__(self):
        self.db_ojb = SessionLocal()

    def bulk_save(self, sql_table, item_list):
        try:
            self.db_ojb.bulk_save_objects(item_list)
            self.db_ojb.commit()
            logger.debug("[+] 插入成功 !!! " + "=========  " + sql_table + "   ========")
            return True
        except Exception as e:
            self.db_ojb.rollback()
            logger.error("产生回滚 !!!   回滚信息: ")
            logger.error(e)
            logger.error("[-] Mysql 插入时产生错误")
            return False

    def insert(self, sql_table, item):
        mysql_table_obj = eval(sql_table)
        try:
            core = mysql_table_obj(**item)
            self.db_ojb.add(core)
            self.db_ojb.commit()
            logger.debug("[+] 插入成功 !!! " + "=========  " + sql_table + "   ========")

        except Exception as e:
            self.db_ojb.rollback()
            logger.error("[-] 产生回滚 !!!   回滚信息: ")
            logger.error(e)
            raise Exception("[-] Mysql 插入时产生错误 ...... fail")

    def query(self, sql_table):
        mysql_table_obj = eval(sql_table)
        result = self.db_ojb.query(mysql_table_obj).all()
        return result

    def delete_log(self, sql_table, spiderId):
        try:
            self.db_ojb.query(sql_table).filter(sql_table.spiderId == spiderId).delete(synchronize_session=False)
            self.db_ojb.commit()
            return True
        except:
            self.db_ojb.rollback()
            logger.error("[-] 产生回滚 !!!   回滚信息: ")
            return False

    def delete(self, sql_table):
        try:
            self.db_ojb.query(sql_table).delete(synchronize_session=False)
            self.db_ojb.commit()
            return True
        except:
            self.db_ojb.rollback()
            logger.error("[-] 产生回滚 !!!   回滚信息: ")
            return False

    def __exit__(self):
        self.db_ojb.close()


from pathlib import Path

from setuptools import setup, find_packages

root = Path(__file__).parent.absolute()
cortex_client_dir = root.parent.parent / "python" / "client"

if not cortex_client_dir.exists():
    raise ModuleNotFoundError(f"cortex client not found in {cortex_client_dir}")

setup(
    name="e2e",
    version="master",  # CORTEX_VERSION
    packages=find_packages(exclude=["tests"]),
    url="https://github.com/cortexlabs/cortex",
    license="Apache License 2.0",
    python_requires=">=3.6",
    install_requires=[
        "requests==2.24.0",
        "jsonschema==3.2.0",
        "pytest==6.1.*",
        "pytest-print==0.2.1",
        "python-dotenv==0.15.0",
        "pyyaml>=5.3.1",
        "boto3>=1.14.53",
        "cortex",
    ],
    dependency_links=[f"file://{cortex_client_dir}#egg=cortex"],
    author="Cortex Labs",
    author_email="dev@cortexlabs.com",
    description="Cortex E2E tests package",
)


from requests import post, get
from utils.logger import register
from time import sleep
from json import loads

def balance(log, token, channel_id, timeout, logging, ID):
    request = post(f"https://discord.com/api/v8/channels/{channel_id}/messages", headers={"authorization": token}, data={"content": "pls bal"})

    if request.status_code != 200 and logging["warning"]:
        register(log, "WARNING", f"Failed to send command `pls bal`. Status code: {request.status_code} (expected 200). Aborting command.")
        return

    if logging["debug"]:
        register(log, "DEBUG", "Successfully sent command `pls bal`.")

    latest_message = None

    for _ in range(0, timeout):
        sleep(1)

        request = get(f"https://discord.com/api/v8/channels/{channel_id}/messages", headers={"authorization": token})

        if request.status_code != 200:
            continue

        latest_message = loads(request.text)[0]

        if latest_message["author"]["id"] == "270904126974590976" and latest_message["referenced_message"]["author"]["id"] == ID:
            if logging["debug"]:
                register(log, "DEBUG", "Got Dank Memer's response to command `pls bal`.")
            break
        else:
            continue

    if latest_message is None or latest_message["author"]["id"] != "270904126974590976":
        if logging["warning"]:
            register(log, "WARNING", f"Timeout exceeded for response from Dank Memer ({timeout} second(s)). Aborting command.")
        return

    return [True, latest_message]


import time
import concurrent.futures

start = time.perf_counter()

def do_something(seconds):
    print(f'Sleeping {seconds} second...\n', end='')
    time.sleep(seconds)
    return f'Done sleeping for {seconds} second(s)'

with concurrent.futures.ThreadPoolExecutor() as executer:
    secs = [5, 4, 3, 2, 1]
    future_objects = [executer.submit(do_something, sec) for sec in secs]
    for f in concurrent.futures.as_completed(future_objects):
        print(f.result())

finish = time.perf_counter()

print(f'Finished in {round(finish - start, 2)} second(s)')


import os
import sys
import time, calendar
import configparser
import logging
import logging.handlers
from datetime import datetime
import pandas as pd

from PyQt5.QAxContainer import *
from PyQt5.QtCore import *
from PyQt5.QtTest import *

from stocklab.kiwoom.config.errorCode import *
from stocklab.kiwoom.config.kiwoomType import *
from stocklab.kiwoom.config.slack import *
from stocklab.db_handler.firbaseRealDBHandler import FirebaseRealDBHandler

class Thread1(QThread):

    def __init__(self, parent, plogger):
        super().__init__(parent)
        self.parent = parent
        self.plogger = plogger
        self.threadCnt = 0

    def run(self):
        while True:
            account_list = self.parent.dynamicCall("GetLoginInfo(QString)", "ACCNO")  # 계좌번호 반환
            self.plogger.info("Count %s ::: account_list : %s" % (self.threadCnt, account_list))
            self.threadCnt += 1
            time.sleep(60)  # 10초마다 계좌정보요구. 접속끊어졌는지 체크

class sysTrading(QAxWidget):
    def __init__(self, parent, mode=None):
        super().__init__()
        ## 환경세팅 #######################################################################################
        self.parent = parent
        self.realType = RealType()
        global logger  # 전체에서 로그를 사용하기 위해 global로 선언을 해줌(전역 변수)
        logger = logging.getLogger('upperLimitPriceTradingLogger')  # 로그 인스턴스를 만든다
        self.set_logger()  # 로그 인스턴스 환경 설정을 셋팅함
        self.slack = MyMsg()  # 슬랙 동작
        self.slack.send_msg(msg="bsking1 슬랙메시지 전송하기")
        self.Fdb = FirebaseRealDBHandler()._client
        logger.debug("Kiwoom() class start.")
        ## config.ini #######################################################################################
        if mode not in ["DEMO_STRADE", "REAL_STRADE", "DEMO_FTRADE", "REAL_FTRADE"]:
            raise Exception("Need to run_mode(DEMO_STRADE or REAL_STRADE or DEMO_FTRADE or REAL_FTRADE)")
        run_mode = mode
        config = configparser.ConfigParser()
        config.read('conf/config.ini')
        self.account = config[run_mode]['account']
        self.use_money = int(config[run_mode]['use_money']) #실제 투자에 사용할 금액
        self.use_money_percent = float(config[run_mode]['use_money_percent']) # 현재 사용안함... 예수금에서 실제 사용할 비율
        self.use_money = int(self.use_money * self.use_money_percent)
        # logger.info("trading money: %s" % self.use_money)
        self.unit_money = int(self.use_money/100)  # 실제 투자에 사용할 금액
        self.maxStockNum = int(config[run_mode]['maxStockNum'])  # 실제 투자에 사용할 금액
        logger.debug("account(config.ini) : %s trading money: %s unit money: %s maxStockNum %s"
                     %(self.account,self.use_money,self.unit_money,self.maxStockNum))

        ######### 초기 셋팅 func들 바로 실행
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1") # 레지스트리에 저장된 api 모듈 불러오기
        self.OnEventConnect.connect(self.login_slot)  # 로그인 관련 이벤트
        self.OnReceiveTrData.connect(self.trdata_slot)  # 트랜잭션 요청 관련 이벤트
        self.OnReceiveMsg.connect(self.msg_slot)
        self.OnReceiveRealData.connect(self.realdata_slot)  # 실시간 이벤트 연결
        self.OnReceiveChejanData.connect(self.chejan_slot)  # 종목 주문체결 관련한 이벤트

        ####### event loop를 실행하기 위한 변수모음
        self.login_event_loop = QEventLoop() #로그인 요청용 이벤트루프
        self.detail_account_info_event_loop = QEventLoop() # 예수금 요청용 이벤트루프
        self.calculator_event_loop = QEventLoop()
        #########################################

        ####### login
        self.block_signal_login_commConnect() #로그인 요청 시그널 포함

        ########### 전체 종목 관리
        self.all_stock_dict = {}
        ###########################
        ####### 계좌 관련된 변수
        self.account_num = ""
        self.account_info_dict = {}
        self.account_stock_dict = {} # unit stock
        self.account1_stock_dict = {}
        self.account2_stock_dict = {}
        self.not_account_stock_dict = {}
        self.deposit = 0 #예수금
        self.output_deposit = 0 #출력가능 금액
        self.total_profit_loss_money = 0 #총평가손익금액
        self.total_profit_loss_rate = 0.0 #총수익률(%)
        ########################################
        ######## 종목 정보 가져오기
        self.portfolio_stock_dict = {}
        self.jango_dict = {}
        ########################
        ########### 종목 분석 용
        self.calcul_data = []
        ##########################################
        ####### 요청 스크린 번호
        self.screen_my_info = "2000" #계좌 관련한 스크린 번호
        self.screen_calculation_stock = "4000" #계산용 스크린 번호
        self.screen_real_stock = "5000" #종목별 할당할 스크린 번호
        self.screen_meme_stock = "6000" #종목별 할당할 주문용스크린 번호
        self.screen_start_stop_real = "1000" #장 시작/종료 실시간 스크린번호
        ########################################

        # trading loop ########################################
        self.isTradingState = "None"
        self.setupSystemTrading()
        self.startSystemTrading()
        #########################################

    # 함수시작 ##############################################################################################
    # 함수 파트 : Logger ##########################################################################
    def set_logger(self):  # 로그 환경을 설정해주는 함수
        fomatter = logging.Formatter(
            '[%(levelname)s|%(lineno)s] %(asctime)s > %(message)s')  # 로그를 남길 방식으로 "[로그레벨|라인번호] 날짜 시간,밀리초 > 메시지" 형식의 포매터를 만든다

        logday = datetime.today().strftime("%Y%m%d")  # 로그 파일 네임에 들어갈 날짜를 만듬 (YYYYmmdd 형태)

        fileMaxByte = 1024 * 1024 * 100  # 파일 최대 용량인 100MB를 변수에 할당 (100MB, 102,400KB)
        fileHandler = logging.handlers.RotatingFileHandler('./log/stock_' + str(logday) + '.log', maxBytes=fileMaxByte,
                                                           backupCount=10)  # 파일에 로그를 출력하는 핸들러 (100MB가 넘으면 최대 10개까지 신규 생성)
        streamHandler = logging.StreamHandler()  # 콘솔에 로그를 출력하는 핸들러

        fileHandler.setFormatter(fomatter)  # 파일에 로그를 출력하는 핸들러에 포매터를 지정
        streamHandler.setFormatter(fomatter)  # 콘솔에 로그를 출력하는 핸들러에 포매터를 지정

        logger.addHandler(fileHandler)  # 로그 인스턴스에 파일에 로그를 출력하는 핸들러를 추가
        logger.addHandler(streamHandler)  # 로그 인스턴스에 콘솔에 로그를 출력하는 핸들러를 추가

        logger.setLevel(logging.INFO)  # 로그 레벨을 디버그로 만듬
        # logger.setLevel(logging.DEBUG)  # 로그 레벨을 디버그로 만듬

    def block_signal_login_commConnect(self):
        logger.debug("func : block_signal_login_commConnect")
        self.dynamicCall("CommConnect()") # 로그인 요청 시그널
        self.login_event_loop.exec_() # 이벤트루프 실행

    def login_slot(self, err_code):
        logger.debug("func : login_slot")
        logger.debug(errors(err_code)[1])
        #로그인 처리가 완료됐으면 이벤트 루프를 종료한다.
        self.login_event_loop.exit()

    def block_get_account_info(self):
        logger.debug("func : block_get_account_info")
        account_list = self.dynamicCall("GetLoginInfo(QString)", "ACCNO") # 계좌번호 반환
        logger.info("account_list : %s" % account_list)
        account_num = account_list.split(';')[0]
        self.account_num = account_num
        self.account_num = self.account # config.ini 에서 읽어온계좌
        logger.info("accout_num : %s" % self.account_num)
        # exit()

    def block_detail_account_info(self, sPrevNext="0"):
        logger.debug("func: block_detail_account_info")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호", "0000")
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호입력매체구분", "00")
        self.dynamicCall("SetInputValue(QString, QString)", "조회구분", "1")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "예수금상세현황요청", "opw00001", sPrevNext, self.screen_my_info)
        self.detail_account_info_event_loop.exec_()

    def block_detail_account_mystock(self, sPrevNext="0"):
        logger.debug("func: block_detail_account_mystock")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호", "0000")
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호입력매체구분", "00")
        self.dynamicCall("SetInputValue(QString, QString)", "조회구분", "1")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "계좌평가잔고내역요청", "opw00018", sPrevNext, self.screen_my_info)

        self.detail_account_info_event_loop.exec_()

    def not_concluded_account(self, sPrevNext="0"):
        logger.debug("func : not_concluded_account")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "체결구분", "1")
        self.dynamicCall("SetInputValue(QString, QString)", "매매구분", "0")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "실시간미체결요청", "opt10075", sPrevNext, self.screen_my_info)

        self.detail_account_info_event_loop.exec_()

    def stop_screen_cancel(self, sScrNo=None):
        logger.debug("func : stop_screen_cancel")
        self.dynamicCall("DisconnectRealData(QString)", sScrNo) # 스크린번호 연결 끊기

    def read_code_xls(self):
        logger.info("func : read_code")
        aPath = "D:/stocklab/bskiwoom/analysys/input/거래종목.xlsx"
        if os.path.exists(aPath): # 해당 경로에 파일이 있는지 체크한다.
            logger.info("aPath exists")
            df = pd.read_excel(aPath, names=["종목코드", "종목명", "EV10", "EV3H", "EV3L", "EV40", "PVOLIC", "거래여부"])
            logger.debug(df)

            for idx, row in df.iterrows(): #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                stock_code = row[0][1:]
                stock_name = row[1]
                stock_EV10 = int(row[2])
                stock_EV3H = int(row[3])
                stock_EV3L = int(row[4])
                stock_EV40 = int(row[5])
                stock_PVOLIC = int(row[6])
                stock_decision = row[7]
                logger.debug(type(row[7]),stock_decision)
                if stock_decision == 1:
                    self.portfolio_stock_dict.update({stock_code:{"종목명":stock_name, "매도": "가능", "매수": "가능"}})
                else :
                    self.portfolio_stock_dict.update({stock_code: {"종목명": stock_name, "매도": "가능", "매수": "불가능"}})
            logger.debug("self.portfolio_stock_dict")
            logger.debug(self.portfolio_stock_dict)

    def screen_number_setting(self):
        logger.debug("func : screen_number_setting")
        screen_overwrite = []

        #계좌평가잔고내역에 있는 종목들
        for code in self.account_stock_dict.keys():
            if code not in screen_overwrite:
                screen_overwrite.append(code)

        #미체결에 있는 종목들
        for order_number in self.not_account_stock_dict.keys():
            code = self.not_account_stock_dict[order_number]['종목코드']

            if code not in screen_overwrite:
                screen_overwrite.append(code)

        #포트폴리로에 담겨있는 종목들
        for code in self.portfolio_stock_dict.keys():

            if code not in screen_overwrite:
                screen_overwrite.append(code)

        # 스크린번호 할당
        cnt = 0
        for code in screen_overwrite:

            temp_screen = int(self.screen_real_stock)
            meme_screen = int(self.screen_meme_stock)

            if (cnt % 50) == 0:
                temp_screen += 1
                self.screen_real_stock = str(temp_screen)

            if (cnt % 50) == 0:
                meme_screen += 1
                self.screen_meme_stock = str(meme_screen)

            if code in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict[code].update({"스크린번호": str(self.screen_real_stock)})
                self.portfolio_stock_dict[code].update({"주문용스크린번호": str(self.screen_meme_stock)})

            elif code not in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict.update({code: {"스크린번호": str(self.screen_real_stock), "주문용스크린번호": str(self.screen_meme_stock),
                                                 "매도": "가능","매수": "불가능"}})
            cnt += 1
        logger.info("Screen settion => self.portfolio_stock_dict")
        logger.info(self.portfolio_stock_dict)

    def day_kiwoom_db(self, code=None, date=None, sPrevNext="0"):
        logger.debug("func : day_kiwoom_db")
        QTest.qWait(3600) #3.6초마다 딜레이를 준다.

        self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
        self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1")

        if date != None:
            self.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)

        self.dynamicCall("CommRqData(QString, QString, int, QString)", "주식일봉차트조회", "opt10081", sPrevNext, self.screen_calculation_stock)  # Tr서버로 전송 -Transaction

        self.calculator_event_loop.exec_()

    def puttoRealDB(self,sCode,psd):
        logger.debug("enter puttoRealDB!!!")
        dbd = {}
        try :
            if self.portfolio_stock_dict[sCode]["매수"] == "가능":
                dbd.update({sCode:{}})
                # dbd[sCode].update([psd["체결시간"],psd["시가"],psd["고가"],psd["저가"],psd["현재가"],psd["거래량"]])

                dbd[sCode].update({"체결시간": psd["체결시간"]})
                dbd[sCode].update({"시가": psd["시가"]})
                dbd[sCode].update({"고가": psd["고가"]})
                dbd[sCode].update({"저가": psd["저가"]})
                dbd[sCode].update({"현재가": psd["현재가"]})
                dbd[sCode].update({"거래량": psd["거래량"]})

                ref = self.Fdb.reference() #기본 위치 지정
                users_ref = ref.child('bbsking1')
                users_ref.push({sCode:dbd,'used':False})
        except: {
            logger.error(EnvironmentError)
        }

            # dbd[sCode].update({"전일대비": psd[]})
            # dbd[sCode].update({"등락율": psd[]})
            # dbd[sCode].update({"(최우선)매도호가": psd[]})
            # dbd[sCode].update({"(최우선)매수호가": psdf})
            # dbd[sCode].update({"누적거래량": psd})

            # ref = db.reference() #기본 위치 지정
            # users_ref = ref.child(sCode)
            # users_ref.push({sCode:dbd})

            # logger.debug(self.Fdb)
            # dir = self.Fdb.reference() #기본 위치 지정
            # dir.update({'야구부':'임꺽정'})
            # ref.update({'A005930':[{'회사명':'삼성전자'},{'1':[[1],[2],[3]]},{'2':[[4],[5],[6]]}]})

            # ref = db.reference() #기본 위치 지정
            # users_ref = ref.child('bbsking1')
            # for item in users_ref.get():
            # snapshot = users_ref.child(item).get()
            # print(snapshot)
            # # type(snapshot) # dict
            # print(list(snapshot[sCode]))
            # type(snapshot[sCode]) # list
            # print(snapshot['used'])
            # if snapshot['used'] == False:
            #     users_ref.child(item).update({'used':True})
    ## 안쓰는 함수들 ######################################################################################
    def get_code_list_by_market(self, market_code):
        logger.debug("func : get_code_list_by_market")
        '''
        종목코드 리스트 받기
        #0:장내, 10:코스닥
        :param market_code: 시장코드 입력
        :return:
        '''
        code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_code)
        code_list = code_list.split(';')[:-1]
        return code_list
    def calculator_fnc(self):
        logger.debug("func : calculator_fnc")
        '''
        종목 분석관련 func 모음
        :return:
        '''

        code_list = self.get_code_list_by_market("10")
        logger.debug("코스닥 갯수 %s " % len(code_list))

        for idx, code in enumerate(code_list):
            self.dynamicCall("DisconnectRealData(QString)", self.screen_calculation_stock)  # 스크린 연결 끊기

            logger.debug("%s / %s :  KOSDAQ Stock Code : %s is updating... " % (idx + 1, len(code_list), code))
            self.day_kiwoom_db(code=code)
    def read_code(self):
        logger.debug("func : read_code")
        if os.path.exists("stocklab/kiwoom/files/condition_stock.txt"): # 해당 경로에 파일이 있는지 체크한다.
            f = open("stocklab/kiwoom/files/condition_stock.txt", "r", encoding="utf8") # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.
            #f = open("files/condition_stock.txt", "r", encoding="utf-16")  # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.

            lines = f.readlines() #파일에 있는 내용들이 모두 읽어와 진다.
            for line in lines: #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                if line != "":
                    ls = line.strip().split("\t")

                    stock_code = ls[0]
                    stock_name = ls[1]
                    #stock_price = int(ls[2].split("\n")[0])
                    stock_price = int(ls[2])
                    stock_price = abs(stock_price)
                    stock_buyDecision = int(ls[3])
                    stock_buyDecision = abs(stock_buyDecision)
                    stock_sellDecision = int(ls[4])
                    stock_sellDecision = abs(stock_sellDecision)

                    self.portfolio_stock_dict.update({stock_code:{"종목명":stock_name, "현재가":stock_price, "매수기준":stock_buyDecision, "매도기준":stock_sellDecision}})
                    #self.portfolio_stock_dict.update({stock_code: {"종목명": stock_name}})
            f.close()
    def merge_dict(self):
        logger.debug("func : merge_dict")
        self.all_stock_dict.update({"계좌평가잔고내역": self.account_stock_dict})
        self.all_stock_dict.update({'미체결종목': self.not_account_stock_dict})
        self.all_stock_dict.update({'포트폴리오종목': self.portfolio_stock_dict})
    def file_delete(self):
        logger.debug("func : file_delete")
        if os.path.isfile("stocklab/kiwoom/files/condition_stock.txt"):
            os.remove("stocklab/kiwoom/files/condition_stock.txt")
            ############################################################################
    def make_ConditionFile(self):
        logger.debug("func : make_ConditionFile")
        if os.path.exists("stocklab/kiwoom/files/condition_stock0.txt"): # 해당 경로에 파일이 있는지 체크한다.
            f = open("stocklab/kiwoom/files/condition_stock0.txt", "r", encoding="utf-16") # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.

            code_list = []
            lines = f.readlines() #파일에 있는 내용들이 모두 읽어와 진다.
            for line in lines: #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                if line != "":
                    ls = line.strip().split("\t")
                    code_list.append(ls[0][1:])
            f.close()

        logger.debug("갯수 %s " % len(code_list))
        for idx, code in enumerate(code_list):
            self.dynamicCall("DisconnectRealData(QString)", self.screen_calculation_stock)  # 스크린 연결 끊기

            logger.debug("%s / %s :  KOSDAQ Stock Code : %s is updating... " % (idx + 1, len(code_list), code))
            self.day_kiwoom_db(code=code)
    def sell_all(self):
        logger.debug("func : sell_all")
        for sCode in self.account_stock_dict.keys():
            asd = self.account_stock_dict[sCode]
            #meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
            if asd['매매가능수량'] > 0:
                order_success = self.dynamicCall(
                    "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                    ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['매매가능수량'], 0,
                     self.realType.SENDTYPE['거래구분']['시장가'], ""]
                )
                if order_success == 0:
                    logger.debug("매도주문 전달 성공")
                    del self.account_stock_dict[sCode]
                else:
                    logger.debug("매도주문 전달 실패")

        for sCode in self.jango_dict.keys():
            asd = self.jango_dict[sCode]
            #meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
            if asd['매매가능수량'] > 0:
                order_success = self.dynamicCall(
                    "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                    ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['보유수량'], 0,
                     self.realType.SENDTYPE['거래구분']['시장가'], ""]
                )
                if order_success == 0:
                    logger.debug("매도주문 전달 성공")
                    del self.account_stock_dict[sCode]
                else:
                    logger.debug("매도주문 전달 실패")
    ###################################################################################################################

    ## CallBack 함수들... ##############################################################################################
    #송수신 메세지 get
    def msg_slot(self, sScrNo, sRQName, sTrCode, msg):
        logger.debug("func : msg_slot")
        logger.debug("")
        logger.debug("스크린: %s, 요청이름: %s, tr코드: %s --- %s" %(sScrNo, sRQName, sTrCode, msg))

    def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
        logger.debug("func : trdata_slot")
        if sRQName == "예수금상세현황요청":
            logger.debug("func : trdata_slot => 예수금상세현황요청")
            deposit = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "예수금")
            self.deposit = int(deposit)

            # use_money = float(self.deposit) * self.use_money_percent
            # self.use_money = int(use_money)
            # self.use_money = self.use_money / 4

            output_deposit = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "출금가능금액")
            self.output_deposit = int(output_deposit)

            logger.info("예수금 : %s" % self.output_deposit)

            self.stop_screen_cancel(self.screen_my_info)

            self.detail_account_info_event_loop.exit()

        elif sRQName == "계좌평가잔고내역요청":
            logger.debug("func : trdata_slot => 계좌평가잔고내역요청")
            total_buy_money = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총매입금액")
            self.total_buy_money = int(total_buy_money)
            total_profit_loss_money = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총평가손익금액")
            self.total_profit_loss_money = int(total_profit_loss_money)
            total_profit_loss_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총수익률(%)")
            self.total_profit_loss_rate = float(total_profit_loss_rate)
            logger.debug("계좌평가잔고내역요청 싱글데이터 : %s - %s - %s" % (total_buy_money, total_profit_loss_money, total_profit_loss_rate))

            rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            for i in range(rows):
                code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목번호")  # 출력 : A039423 // 알파벳 A는 장내주식, J는 ELW종목, Q는 ETN종목
                code = code.strip()[1:]

                code_nm = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")  # 출럭 : 한국기업평가
                stock_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "보유수량")  # 보유수량 : 000000000000010
                buy_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입가")  # 매입가 : 000000000054100
                learn_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "수익률(%)")  # 수익률 : -000000001.94
                current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")  # 현재가 : 000000003450
                total_chegual_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입금액")
                possible_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매매가능수량")
                today_buyquantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"금일매수수량")
                today_sellquantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"금일매도수량")

                logger.debug("종목코드: %s - 종목명: %s - 보유수량: %s - 매매가능수량: %s - 금일매수수량: %s - 금일매도수량: %s - 매입가:%s - 수익률: %s - 현재가: %s" % (
                    code, code_nm, stock_quantity, possible_quantity, today_buyquantity, today_sellquantity, buy_price, learn_rate, current_price))

                if code in self.account_stock_dict:  # dictionary 에 해당 종목이 있나 확인
                    pass
                else:
                    self.account_stock_dict[code] = {}

                code_nm = code_nm.strip()
                stock_quantity = int(stock_quantity.strip())
                buy_price = int(buy_price.strip())
                learn_rate = float(learn_rate.strip())
                current_price = int(current_price.strip())
                total_chegual_price = int(total_chegual_price.strip())
                possible_quantity = int(possible_quantity.strip())-int(today_buyquantity.strip())
                today_buyquantity = int(today_buyquantity.strip())
                today_sellquantity = int(today_sellquantity.strip())

                self.account_stock_dict[code].update({"종목명": code_nm})
                self.account_stock_dict[code].update({"보유수량": stock_quantity})
                self.account_stock_dict[code].update({"매입가": buy_price})
                self.account_stock_dict[code].update({"수익률": learn_rate})
                self.account_stock_dict[code].update({"현재가": current_price})
                self.account_stock_dict[code].update({"매입금액": total_chegual_price})
                self.account_stock_dict[code].update({'매매가능수량' : possible_quantity})
                self.account_stock_dict[code].update({'금일매수수량': today_buyquantity})
                self.account_stock_dict[code].update({'금일매도수량': today_sellquantity})
                self.account_stock_dict[code].update({'매도': "가능"})

            logger.info("sPreNext : %s" % sPrevNext)

            if sPrevNext == "2":
                self.detail_account_mystock(sPrevNext="2")
            else:
                logger.debug("계좌에 가지고 있는 종목은 %s " % rows)
                self.account_info_dict.update(
                    {self.account_num:
                        {
                            "투입금액": self.use_money,
                            "단위금액": self.unit_money,
                            "최대거래종목수": self.maxStockNum,
                            "총매입금액": self.total_buy_money,
                            "총평가손익금액": self.total_profit_loss_money,
                            "총수익률(%)": self.total_profit_loss_rate,
                            "보유종목수": rows,
                            "매수가능": "가능"
                        }
                    })
                if rows >= self.account_info_dict[self.account_num]["최대거래종목수"]:
                    self.account_info_dict[self.account_num].update({"매수가능": "불가능"})
                logger.info(self.account_info_dict)
                self.detail_account_info_event_loop.exit()

        elif sRQName == "실시간미체결요청":
            logger.debug("func : trdata_slot => 실시간미체결요청")
            rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            for i in range(rows):
                code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목코드")
                code_nm = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
                order_no = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문번호")
                order_status = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                "주문상태")  # 접수,확인,체결
                order_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                  "주문수량")
                order_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "주문가격")
                order_gubun = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "주문구분")  # -매도, +매수, -매도정정, +매수정정
                not_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                "미체결수량")
                ok_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "체결량")

                code = code.strip()
                code_nm = code_nm.strip()
                order_no = int(order_no.strip())
                order_status = order_status.strip()
                order_quantity = int(order_quantity.strip())
                order_price = int(order_price.strip())
                order_gubun = order_gubun.strip().lstrip('+').lstrip('-')
                not_quantity = int(not_quantity.strip())
                ok_quantity = int(ok_quantity.strip())

                if order_no in self.not_account_stock_dict:
                    pass
                else:
                    self.not_account_stock_dict[order_no] = {}

                self.not_account_stock_dict[order_no].update({'종목코드': code})
                self.not_account_stock_dict[order_no].update({'종목명': code_nm})
                self.not_account_stock_dict[order_no].update({'주문번호': order_no})
                self.not_account_stock_dict[order_no].update({'주문상태': order_status})
                self.not_account_stock_dict[order_no].update({'주문수량': order_quantity})
                self.not_account_stock_dict[order_no].update({'주문가격': order_price})
                self.not_account_stock_dict[order_no].update({'주문구분': order_gubun})
                self.not_account_stock_dict[order_no].update({'미체결수량': not_quantity})
                self.not_account_stock_dict[order_no].update({'체결량': ok_quantity})

                logger.info("미체결 종목 : %s "  % self.not_account_stock_dict[order_no])

            self.detail_account_info_event_loop.exit()

        elif sRQName == "주식일봉차트조회":
            logger.info("func : trdata_slot => 주식일봉차트조회")
            code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드")
            code = code.strip()
            # data = self.dynamicCall("GetCommDataEx(QString, QString)", sTrCode, sRQName)
            # [[‘’, ‘현재가’, ‘거래량’, ‘거래대금’, ‘날짜’, ‘시가’, ‘고가’, ‘저가’. ‘’], [‘’, ‘현재가’, ’거래량’, ‘거래대금’, ‘날짜’, ‘시가’, ‘고가’, ‘저가’, ‘’]. […]]

            cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            logger.info("남은 일자 수 %s" % cnt)
            for i in range(cnt):
                data = []

                current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")  # 출력 : 000070
                value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래량")  # 출력 : 000070
                trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래대금")  # 출력 : 000070
                date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "일자")  # 출력 : 000070
                start_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "시가")  # 출력 : 000070
                high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가")  # 출력 : 000070
                low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "저가")  # 출력 : 000070

                data.append("")
                data.append(current_price.strip())
                data.append(value.strip())
                data.append(trading_value.strip())
                data.append(date.strip())
                data.append(start_price.strip())
                data.append(high_price.strip())
                data.append(low_price.strip())
                data.append("")
                self.calcul_data.append(data.copy())

            if sPrevNext == "2":
                self.day_kiwoom_db(code=code, sPrevNext=sPrevNext)
            else:
                logger.debug("총 일수 %s" % len(self.calcul_data))

                self.calcul_data.clear()
                self.calculator_event_loop.exit()

    # 실시간 데이터 얻어오기
    def realdata_slot(self, sCode, sRealType, sRealData):
        logger.debug("func : realdata_slot")
        if sRealType == "장시작시간":
            fid = self.realType.REALTYPE[sRealType]['장운영구분']  # (0:장시작전, 2:장종료전(20분), 3:장시작, 4,8:장종료(30분), 9:장마감)
            value = self.dynamicCall("GetCommRealData(QString, int)", sCode, fid)

            if value == '0':
                logger.info("장 시작 전")
            elif value == '3':
                logger.info("장 시작")
            elif value == "2":
                logger.info("장 종료, 동시호가로 넘어감")
            elif value == "4":
                logger.info("3시30분 장 종료")
                for code in self.portfolio_stock_dict.keys():
                    self.dynamicCall("SetRealRemove(QString, QString)", self.portfolio_stock_dict[code]['스크린번호'], code)
                QTest.qWait(5000)
                exit()

        elif sRealType == "주식체결":

            a = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['체결시간'])  # 출력 HHMMSS
            b = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['현재가'])  # 출력 : +(-)2520
            b = abs(int(b))

            c = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['전일대비'])  # 출력 : +(-)2520
            c = abs(int(c))

            d = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['등락율'])  # 출력 : +(-)12.98
            d = float(d)

            e = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['(최우선)매도호가'])  # 출력 : +(-)2520
            e = abs(int(e))

            f = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['(최우선)매수호가'])  # 출력 : +(-)2515
            f = abs(int(f))

            g = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['거래량'])  # 출력 : +240124  매수일때, -2034 매도일 때
            g = abs(int(g))

            h = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['누적거래량'])  # 출력 : 240124
            h = abs(int(h))

            i = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['고가'])  # 출력 : +(-)2530
            i = abs(int(i))

            j = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['시가'])  # 출력 : +(-)2530
            j = abs(int(j))

            k = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['저가'])  # 출력 : +(-)2530
            k = abs(int(k))

            if sCode not in self.portfolio_stock_dict:
                logging.error(" 포트폴리오에 없는종목 %s" % sCode)
                return
                # self.portfolio_stock_dict.update({sCode:{}})

            self.portfolio_stock_dict[sCode].update({"체결시간": a})
            self.portfolio_stock_dict[sCode].update({"현재가": b})
            self.portfolio_stock_dict[sCode].update({"전일대비": c})
            self.portfolio_stock_dict[sCode].update({"등락율": d})
            self.portfolio_stock_dict[sCode].update({"(최우선)매도호가": e})
            self.portfolio_stock_dict[sCode].update({"(최우선)매수호가": f})
            self.portfolio_stock_dict[sCode].update({"거래량": g})
            self.portfolio_stock_dict[sCode].update({"누적거래량": h})
            self.portfolio_stock_dict[sCode].update({"고가": i})
            self.portfolio_stock_dict[sCode].update({"시가": j})
            self.portfolio_stock_dict[sCode].update({"저가": k})

            self.puttoRealDB(sCode,self.portfolio_stock_dict[sCode])

            if sCode in self.account_stock_dict.keys(): # and sCode not in self.jango_dict.keys():
                asd = self.account_stock_dict[sCode]
                psd = self.portfolio_stock_dict[sCode]
                logger.debug("매도콜백")
                logger.debug(asd)

                meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
                if sCode in self.account2_stock_dict:
                    if asd['매도'] == "가능" and asd['보유수량'] > 0 and asd['금일매도수량'] == 0 and meme_rate > 30:  # 손익절 매도

                        order_success = self.dynamicCall(
                            "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                            ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode,
                             int(asd['보유수량'] / 2), 0, self.realType.SENDTYPE['거래구분']['시장가'], ""]
                        )
                        if order_success == 0:
                            logger.info("매도주문 전달 성공")
                            self.slack.send_msg(msg="bsking1 매도주문 전달 성공")
                            asd.update({'매도': "불가능"})
                            del self.account2_stock_dict[sCode]
                            # del self.portfolio_stock_dict[sCode]
                        else:
                            logger.info("매도주문 전달 실패")

                # meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
                if asd['매도'] == "가능" and asd['보유수량'] > 0 and meme_rate < -15 : # 손절 전액매도
                    order_success = self.dynamicCall(
                        "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                        ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['보유수량'], 0, self.realType.SENDTYPE['거래구분']['시장가'], ""]
                    )
                    if order_success == 0:
                        logger.info("매도주문 전달 성공")
                        self.slack.send_msg(msg="bsking1 매도주문 전달 성공")
                        asd.update({'매도': "불가능"})
                        del self.account_stock_dict[sCode]
                        if sCode in self.account2_stock_dict:
                            del self.account2_stock_dict[sCode]
                        del self.portfolio_stock_dict[sCode]
                    else:
                        logger.info("매도주문 전달 실패")

    # 실시간 체결 정보
    def chejan_slot(self, sGubun, nItemCnt, sFidList):
        logger.debug("func : chejan_slot")
        if int(sGubun) == 0: #주문체결
            account_num = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['계좌번호'])
            sCode = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목코드'])[1:]
            stock_name = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목명'])
            stock_name = stock_name.strip()

            origin_order_number = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['원주문번호'])  # 출력 : defaluse : "000000"
            order_number = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문번호'])  # 출럭: 0115061 마지막 주문번호

            order_status = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문상태'])  # 출력: 접수, 확인, 체결
            order_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문수량'])  # 출력 : 3
            order_quan = int(order_quan)

            order_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문가격'])  # 출력: 21000
            order_price = int(order_price)

            not_chegual_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['미체결수량'])  # 출력: 15, default: 0
            not_chegual_quan = int(not_chegual_quan)

            order_gubun = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문구분'])  # 출력: -매도, +매수
            order_gubun = order_gubun.strip().lstrip('+').lstrip('-')

            chegual_time_str = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문/체결시간'])  # 출력: '151028'

            chegual_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결가'])  # 출력: 2110  default : ''
            if chegual_price == '':
                chegual_price = 0
            else:
                chegual_price = int(chegual_price)

            chegual_quantity = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결량'])  # 출력: 5  default : ''
            if chegual_quantity == '':
                chegual_quantity = 0
            else:
                chegual_quantity = int(chegual_quantity)

            current_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['현재가'])  # 출력: -6000
            current_price = abs(int(current_price))

            first_sell_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매도호가'])  # 출력: -6010
            first_sell_price = abs(int(first_sell_price))

            first_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매수호가'])  # 출력: -6000
            first_buy_price = abs(int(first_buy_price))

            ######## 새로 들어온 주문이면 주문번호 할당
            if order_number not in self.not_account_stock_dict.keys():
                self.not_account_stock_dict.update({order_number: {}})

            self.not_account_stock_dict[order_number].update({"종목코드": sCode})
            self.not_account_stock_dict[order_number].update({"주문번호": order_number})
            self.not_account_stock_dict[order_number].update({"종목명": stock_name})
            self.not_account_stock_dict[order_number].update({"주문상태": order_status})
            self.not_account_stock_dict[order_number].update({"주문수량": order_quan})
            self.not_account_stock_dict[order_number].update({"주문가격": order_price})
            self.not_account_stock_dict[order_number].update({"미체결수량": not_chegual_quan})
            self.not_account_stock_dict[order_number].update({"원주문번호": origin_order_number})
            self.not_account_stock_dict[order_number].update({"주문구분": order_gubun})
            self.not_account_stock_dict[order_number].update({"주문/체결시간": chegual_time_str})
            self.not_account_stock_dict[order_number].update({"체결가": chegual_price})
            self.not_account_stock_dict[order_number].update({"체결량": chegual_quantity})
            self.not_account_stock_dict[order_number].update({"현재가": current_price})
            self.not_account_stock_dict[order_number].update({"(최우선)매도호가": first_sell_price})
            self.not_account_stock_dict[order_number].update({"(최우선)매수호가": first_buy_price})

        elif int(sGubun) == 1: #잔고

            account_num = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['계좌번호'])
            sCode = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['종목코드'])[1:]

            stock_name = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['종목명'])
            stock_name = stock_name.strip()

            current_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['현재가'])
            current_price = abs(int(current_price))

            stock_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['보유수량'])
            stock_quan = int(stock_quan)

            like_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['주문가능수량'])
            like_quan = int(like_quan)

            buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['매입단가'])
            buy_price = abs(int(buy_price))

            total_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['총매입가']) # 계좌에 있는 종목의 총매입가
            total_buy_price = int(total_buy_price)

            meme_gubun = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['매도매수구분'])
            meme_gubun = self.realType.REALTYPE['매도수구분'][meme_gubun] # 1: 매수, 0: 매도(?)

            first_sell_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['(최우선)매도호가'])
            first_sell_price = abs(int(first_sell_price))

            first_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['(최우선)매수호가'])
            first_buy_price = abs(int(first_buy_price))

            if sCode not in self.jango_dict.keys():
                self.jango_dict.update({sCode:{}})

            self.jango_dict[sCode].update({"현재가": current_price})
            self.jango_dict[sCode].update({"종목코드": sCode})
            self.jango_dict[sCode].update({"종목명": stock_name})
            self.jango_dict[sCode].update({"보유수량": stock_quan})
            self.jango_dict[sCode].update({"주문가능수량": like_quan})
            self.jango_dict[sCode].update({"매입단가": buy_price})
            self.jango_dict[sCode].update({"총매입가": total_buy_price})
            self.jango_dict[sCode].update({"매도매수구분": meme_gubun})
            self.jango_dict[sCode].update({"(최우선)매도호가": first_sell_price})
            self.jango_dict[sCode].update({"(최우선)매수호가": first_buy_price})

            if stock_quan == 0:
                del self.jango_dict[sCode]
                #self.slack.send_msg(msg=("%s 매도완료"%self.jango_dict[sCode]["종목명"]))
                logger.debug("매도완료")
            else :
                #self.slack.send_msg(msg=("%s 체결 %s주" %(self.jango_dict[sCode]["종목명"],stock_quan)))
                #logger.debug("%s 체결 %s주" %(self.jango_dict[sCode]["종목명"],stock_quan))
                logger.debug("매매체결")

    ##########################################################################################################
    def setupSystemTrading(self):
        try:
            logger.info("setupSystemTrading 시작")
            if 0 :
                #  self.testFirebaseDB()
                logger.info("setupSystemTrading 끝")
                exit()

            # self.account_num
            self.block_get_account_info()  # 계좌번호 가져오기
            # self.deposit : 예수금, self.output_deposit :출금가능금액 // self.use_money?
            self.block_detail_account_info()  # 예수금 요청 시그널 포함
            #self.total_buy_money :총매입금액, self.total_profit_loss_money :총평가손익금액, self.total_profit_loss_rate : 총수익률(%)
            # account_stock_dict[종목코드] : 종목명: %s - 보유수량: %s - 매입가:%s - 수익률: %s - 현재가: %s
            self.block_detail_account_mystock()  # 계좌평가잔고내역 요청 시그널 포함
            # not_account_stock_dict[order_no] : 종목코드 종목명 주문번호 주문상태 주문수량 주문가격 주문구분 미체결수량 체결량
            QTimer.singleShot(5000, self.not_concluded_account)  # 5초 뒤에 미체결 종목들 가져오기 실행
            QTest.qWait(10000)
            self.isTradingState = "OnTrading"
            # portfolio_stock_dict[종목명] : 현재가 매수기준 매도기준
            # self.read_code()
            self.read_code_xls()
             # 번호할당 portfolio_stock_dict <- portfolio_stock_dict + account_stock_dict + not_account_stock_dict
            self.screen_number_setting()
            QTest.qWait(5000)

            t_now = datetime.now()
            t_9 = t_now.replace(hour=9, minute=0, second=0, microsecond=0)
            t_start = t_now.replace(hour=9, minute=5, second=0, microsecond=0)
            t_sell = t_now.replace(hour=15, minute=00, second=0, microsecond=0)
            t_exit = t_now.replace(hour=15, minute=20, second=0, microsecond=0)
            today = datetime.today().weekday()
            if today == 5 or today == 6:  # 토요일이나 일요일이면 자동 종료
                logger.info("Today is Saturday or Sunday.")
                exit()

            if t_exit < t_now:  # PM 03:20 ~ :프로그램 종료
                logger.info("PM 03:20 ~ :프로그램 종료!")
                if 0 :
                    self.isTradingState = "MakeFile"
                    self.file_delete()
                    self.make_ConditionFile()
                exit()
            time.sleep(3)

            logger.info('실시간 수신 관련 함수')
            logger.debug(self.portfolio_stock_dict)
            # 실시간 수신 관련 함수
            self.dynamicCall("SetRealReg(QString, QString, QString, QString)", self.screen_start_stop_real, '',
                             self.realType.REALTYPE['장시작시간']['장운영구분'], "0")

            # exit()

            for code in self.portfolio_stock_dict.keys():
                screen_num = self.portfolio_stock_dict[code]['스크린번호']
                fids = self.realType.REALTYPE['주식체결']['체결시간']
                self.dynamicCall("SetRealReg(QString, QString, QString, QString)", screen_num, code, fids, "1")

        except Exception as ex:
            logger.debug('`main -> exception! ' + str(ex) + '`')

    def startSystemTrading(self):
        # Thread loop ########################################
        h1 = Thread1(self,logger)
        h1.start()
        #########################################
        pass


from .utils import *

def parse_playlist_items(results):
    songs = []
    count = 1
    for result in results:
        count += 1
        if 'musicResponsiveListItemRenderer' not in result:
            continue
        data = result['musicResponsiveListItemRenderer']

        try:
            # if playlist is not owned, the playlist item can't be interacted with
            videoId = setVideoId = None
            like = None

            # if item is not playable, there is no videoId
            if 'playNavigationEndpoint' in nav(data, PLAY_BUTTON):
                videoId = nav(data,
                              PLAY_BUTTON)['playNavigationEndpoint']['watchEndpoint']['videoId']

                for item in nav(data, MENU_ITEMS):
                    if 'menuServiceItemRenderer' in item and 'playlistEditEndpoint' in nav(
                            item, MENU_SERVICE):
                        setVideoId = nav(
                            item, MENU_SERVICE)['playlistEditEndpoint']['actions'][0]['setVideoId']
                        break

                if 'menu' in data:
                    like = nav(data, MENU_LIKE_STATUS, True)

            title = get_item_text(data, 0)
            if title == 'Song deleted':
                continue

            artists = parse_song_artists(data, 1)

            album = parse_song_album(data, 2)

            duration = None
            if 'fixedColumns' in data:
                if 'simpleText' in data['fixedColumns'][0][
                        'musicResponsiveListItemFixedColumnRenderer']['text']:
                    duration = data['fixedColumns'][0][
                        'musicResponsiveListItemFixedColumnRenderer']['text']['simpleText']
                else:
                    duration = data['fixedColumns'][0][
                        'musicResponsiveListItemFixedColumnRenderer']['text']['runs'][0]['text']

            thumbnails = None
            if 'thumbnail' in data:
                thumbnails = nav(data, THUMBNAILS)

            song = {
                'videoId': videoId,
                'title': title,
                'artists': artists,
                'album': album,
                'likeStatus': like,
                'thumbnails': thumbnails
            }
            if duration:
                song['duration'] = duration
            if setVideoId:
                song['setVideoId'] = setVideoId

            songs.append(song)

        except Exception as e:
            print("Item " + str(count) + ": " + str(e))

    return songs


"""
1. Use functions to:
    - read a complex number from the console,
    - write a complex number to the console,
    - implement each required functionality.
2. Functions communicate using input parameter(s) and the return statement (DO NOT use global variables)
    - Each complex number should be represented as a list, tuple or dictionary
    - (e.g. 1-2i as [1, -2], (1, -2) or {'real': 1, 'imag': -2} respectively).
    - To access or modify numbers, use getter and setter functions.
3. Separate input/output functions (those using print and input statements) from those performing the calculations (see program.py)
4. Provide the user with a menu-driven console-based user interface.
    - Input data should be read from the console and the results printed to the console.
    - At each step, the program must provide the user the context of the operation (do not display an empty prompt).
"""

# Function section
# (write all non-UI functions in this section)
# There should be no print or input statements below this comment
# Each function should do one thing only
# Functions communicate using input parameters and their return values
# print('Hello A2'!) -> prints aren't allowed here!

def create_complex(real, imaginary):
    complex_number = []
    complex_number.append(real)
    complex_number.append(imaginary)
    return complex_number

def get_real(number):
    return number[0]

def get_imaginary(number):
    return number[1]

def to_string(number):
    real = get_real(number)
    imaginary = get_imaginary(number)
    if real != 0 and imaginary != 0:
        if imaginary < 0:
            return str(real) + '' + str(imaginary) + 'i'
        else:
            return str(real) + '+' + str(imaginary) + 'i'
    elif real == 0 and imaginary != 0:
        return str(imaginary) + 'i'
    else:
        return str(real)

def get_real_sequence(list):
    """
    Determining the length and the last index of the longest sequence of real numbers
    :param list: The list we're about to check
    :return: A list, where the first element is the length, the second being the last index
    """
    sequence_data = []
    final_position = 0
    temporary_position = 0
    maximum_length = 0
    temporary_length = 0
    for index, number in enumerate(list):
        if get_imaginary(number) == 0:
            temporary_length += 1
            temporary_position = index
        else:
            if temporary_length >= maximum_length:
                maximum_length = temporary_length
                final_position = temporary_position
            temporary_length = 0
    if temporary_length >= maximum_length:
        maximum_length = temporary_length
        final_position = temporary_position
    sequence_data.append(maximum_length)
    sequence_data.append(final_position)
    return sequence_data

def get_distinct_sequence(list):
    sequence_data = []
    previous_element = list[0]
    maximum_length = 0
    sequence_length = 0
    final_index = 0
    index = 0
    for i in range(1, len(list)):
        number = list[i]
        if get_imaginary(number) != get_imaginary(previous_element) or get_real(number) != get_real(previous_element):
            sequence_length += 1
            index = i
        else:
            if sequence_length >= maximum_length:
                maximum_length = sequence_length
                final_index = i
            sequence_length = 0
        previous_element = number
    if sequence_length >= maximum_length:
        maximum_length = sequence_length
        final_index = i
    sequence_data.append(maximum_length)
    sequence_data.append(final_index)
    return sequence_data

# UI section
# (write all functions that have input or print statements here).
# Ideally, this section should not contain any calculations relevant to program functionalities

def read_complex():
    """
    Read a complex number
    :return: The complex number
    """
    real = int(input("Give the real part: "))
    imaginary = int(input("Give the imaginary part: "))
    return create_complex(real, imaginary)

def read_complex_ui(complex_list):
    """
    Add a list of complex numbers
    :param complex_list: The initial list of complex numbers
    :return: -
    """
    number_of_numbers = int(input("How many numbers do you want to add to the list? "))
    for i in range(number_of_numbers):
        complex_number = read_complex()
        complex_list.append(complex_number)
        print("Complex number added!")

def show_complex_ui(complex_list):
    for complex_nr in complex_list:
        print(to_string(complex_nr))

def real_sequence_ui(complex_list):
    """
    Printing the longest sequence of real numbers from the list
    :param complex_list: The list of complex numbers
    :return:
    """
    # Getting the length and the last index of the longest sequence
    sequence_data = get_real_sequence(complex_list)
    # Calculating the margins of the sequence
    start_position = sequence_data[1] - sequence_data[0] + 1
    final_position = sequence_data[1]
    # Printing the elements of the sequence
    for i in range(start_position, final_position + 1):
        print(to_string(complex_list[i]))

def distinct_sequence_ui(complex_list):
    sequence_data = get_distinct_sequence(complex_list)
    final_position = sequence_data[1]
    start_position = sequence_data[1] - sequence_data[0]
    for i in range(start_position, final_position + 1):
        print(to_string(complex_list[i]))

def print_menu():
    print("1. Read several complex numbers")
    print("2. Display the list")
    print("3. Display the first sequence (Longest sequence of real numbers)")
    print("4. Display the second sequence (Longest sequence of distinct numbers")
    print("0. Exit")

def start():
    """
    Steps:
        1. Initialised the list for complex numbers
        2. Also initialised a dictionary for the menu commands
        3. Printing the menu
        4. Reading user input and handling it
    :return:
    """
    complex_list = []
    list_init(complex_list)
    command_dictionary = {
        '1': read_complex_ui,
        '2': show_complex_ui,
        '3': real_sequence_ui,
        '4': distinct_sequence_ui,
    }
    done = False
    while not done:
        print_menu()
        command = input("Enter your command: ")
        if command == '0':
            done = True
        elif command not in command_dictionary:
            print("Invalid command")
        else:
            instruction = command_dictionary[command]
            instruction(complex_list)

def list_init(complex_list):
    """
    Adding some initial complex numbers to our list
    :param complex_list: The list used to store the complex numbers
    :return: -
    """
    complex_list.append(create_complex(-1, 3))
    complex_list.append(create_complex(7, 0))
    complex_list.append(create_complex(7, 0))
    complex_list.append(create_complex(1, 7))
    complex_list.append(create_complex(3, -7))
    complex_list.append(create_complex(9, 0))
    complex_list.append(create_complex(6, 0))
    complex_list.append(create_complex(-4, 1))

start()