Add KissMe framework and console command line tool
This commit is contained in:
582
KissMe.xcodeproj/project.pbxproj
Normal file
582
KissMe.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,582 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EAF2A0A80EC00962D48 /* KissMe.docc */; };
|
||||
341F5EB62A0A80EC00962D48 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EAB2A0A80EC00962D48 /* KissMe.framework */; };
|
||||
341F5EBB2A0A80EC00962D48 /* KissMeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EBA2A0A80EC00962D48 /* KissMeTests.swift */; };
|
||||
341F5EBC2A0A80EC00962D48 /* KissMe.h in Headers */ = {isa = PBXBuildFile; fileRef = 341F5EAE2A0A80EC00962D48 /* KissMe.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
341F5EDE2A0F300100962D48 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EDD2A0F300100962D48 /* Request.swift */; };
|
||||
341F5EE12A0F373B00962D48 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EE02A0F373B00962D48 /* Login.swift */; };
|
||||
341F5EE52A0F3EF400962D48 /* DomesticStock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EE42A0F3EF400962D48 /* DomesticStock.swift */; };
|
||||
341F5EE92A0F87FB00962D48 /* DomesticStockPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EE82A0F87FB00962D48 /* DomesticStockPrice.swift */; };
|
||||
341F5EEC2A0F883900962D48 /* ForeignStock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EEB2A0F883900962D48 /* ForeignStock.swift */; };
|
||||
341F5EEE2A0F884300962D48 /* ForeignStockPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EED2A0F884300962D48 /* ForeignStockPrice.swift */; };
|
||||
341F5EF02A0F886600962D48 /* ForeignFutures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EEF2A0F886600962D48 /* ForeignFutures.swift */; };
|
||||
341F5EF22A0F887200962D48 /* DomesticFutures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EF12A0F887200962D48 /* DomesticFutures.swift */; };
|
||||
341F5EF52A0F891200962D48 /* KissAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EF42A0F891200962D48 /* KissAccount.swift */; };
|
||||
341F5EF72A0F8B0500962D48 /* DomesticStockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EF62A0F8B0500962D48 /* DomesticStockResult.swift */; };
|
||||
341F5EF92A0F907300962D48 /* DomesticStockPriceResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EF82A0F907300962D48 /* DomesticStockPriceResult.swift */; };
|
||||
341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EFA2A10909D00962D48 /* LoginResult.swift */; };
|
||||
341F5EFD2A10931B00962D48 /* DomesticStockSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EFC2A10931B00962D48 /* DomesticStockSearch.swift */; };
|
||||
341F5EFF2A10955D00962D48 /* OrderRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EFE2A10955D00962D48 /* OrderRequest.swift */; };
|
||||
341F5F012A11155100962D48 /* DomesticStockSearchResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F002A11155100962D48 /* DomesticStockSearchResult.swift */; };
|
||||
341F5F032A11A2BC00962D48 /* Credential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F022A11A2BC00962D48 /* Credential.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
341F5EB72A0A80EC00962D48 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 341F5EA22A0A80EC00962D48 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 341F5EAA2A0A80EC00962D48;
|
||||
remoteInfo = KissMe;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
341F5EAB2A0A80EC00962D48 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
341F5EAE2A0A80EC00962D48 /* KissMe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KissMe.h; sourceTree = "<group>"; };
|
||||
341F5EAF2A0A80EC00962D48 /* KissMe.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = KissMe.docc; sourceTree = "<group>"; };
|
||||
341F5EB52A0A80EC00962D48 /* KissMeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KissMeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
341F5EBA2A0A80EC00962D48 /* KissMeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissMeTests.swift; sourceTree = "<group>"; };
|
||||
341F5EDD2A0F300100962D48 /* Request.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
|
||||
341F5EE02A0F373B00962D48 /* Login.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Login.swift; sourceTree = "<group>"; };
|
||||
341F5EE42A0F3EF400962D48 /* DomesticStock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStock.swift; sourceTree = "<group>"; };
|
||||
341F5EE82A0F87FB00962D48 /* DomesticStockPrice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockPrice.swift; sourceTree = "<group>"; };
|
||||
341F5EEB2A0F883900962D48 /* ForeignStock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForeignStock.swift; sourceTree = "<group>"; };
|
||||
341F5EED2A0F884300962D48 /* ForeignStockPrice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForeignStockPrice.swift; sourceTree = "<group>"; };
|
||||
341F5EEF2A0F886600962D48 /* ForeignFutures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForeignFutures.swift; sourceTree = "<group>"; };
|
||||
341F5EF12A0F887200962D48 /* DomesticFutures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticFutures.swift; sourceTree = "<group>"; };
|
||||
341F5EF42A0F891200962D48 /* KissAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissAccount.swift; sourceTree = "<group>"; };
|
||||
341F5EF62A0F8B0500962D48 /* DomesticStockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockResult.swift; sourceTree = "<group>"; };
|
||||
341F5EF82A0F907300962D48 /* DomesticStockPriceResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockPriceResult.swift; sourceTree = "<group>"; };
|
||||
341F5EFA2A10909D00962D48 /* LoginResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginResult.swift; sourceTree = "<group>"; };
|
||||
341F5EFC2A10931B00962D48 /* DomesticStockSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockSearch.swift; sourceTree = "<group>"; };
|
||||
341F5EFE2A10955D00962D48 /* OrderRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderRequest.swift; sourceTree = "<group>"; };
|
||||
341F5F002A11155100962D48 /* DomesticStockSearchResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticStockSearchResult.swift; sourceTree = "<group>"; };
|
||||
341F5F022A11A2BC00962D48 /* Credential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credential.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
341F5EA82A0A80EC00962D48 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
341F5EB22A0A80EC00962D48 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EB62A0A80EC00962D48 /* KissMe.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
341F5EA12A0A80EC00962D48 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EAD2A0A80EC00962D48 /* KissMe */,
|
||||
341F5EB92A0A80EC00962D48 /* KissMeTests */,
|
||||
341F5EAC2A0A80EC00962D48 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EAC2A0A80EC00962D48 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EAB2A0A80EC00962D48 /* KissMe.framework */,
|
||||
341F5EB52A0A80EC00962D48 /* KissMeTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EAD2A0A80EC00962D48 /* KissMe */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EF32A0F88AC00962D48 /* Common */,
|
||||
341F5EEA2A0F882300962D48 /* Foreign */,
|
||||
341F5EE62A0F3EFB00962D48 /* Domestic */,
|
||||
341F5EDF2A0F372000962D48 /* Login */,
|
||||
341F5EAE2A0A80EC00962D48 /* KissMe.h */,
|
||||
341F5EAF2A0A80EC00962D48 /* KissMe.docc */,
|
||||
341F5EF42A0F891200962D48 /* KissAccount.swift */,
|
||||
);
|
||||
path = KissMe;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EB92A0A80EC00962D48 /* KissMeTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EBA2A0A80EC00962D48 /* KissMeTests.swift */,
|
||||
);
|
||||
path = KissMeTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EDF2A0F372000962D48 /* Login */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EE02A0F373B00962D48 /* Login.swift */,
|
||||
341F5EFA2A10909D00962D48 /* LoginResult.swift */,
|
||||
);
|
||||
path = Login;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EE62A0F3EFB00962D48 /* Domestic */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EE42A0F3EF400962D48 /* DomesticStock.swift */,
|
||||
341F5EF62A0F8B0500962D48 /* DomesticStockResult.swift */,
|
||||
341F5EE82A0F87FB00962D48 /* DomesticStockPrice.swift */,
|
||||
341F5EF82A0F907300962D48 /* DomesticStockPriceResult.swift */,
|
||||
341F5EFC2A10931B00962D48 /* DomesticStockSearch.swift */,
|
||||
341F5F002A11155100962D48 /* DomesticStockSearchResult.swift */,
|
||||
341F5EF12A0F887200962D48 /* DomesticFutures.swift */,
|
||||
);
|
||||
path = Domestic;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EEA2A0F882300962D48 /* Foreign */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EEB2A0F883900962D48 /* ForeignStock.swift */,
|
||||
341F5EED2A0F884300962D48 /* ForeignStockPrice.swift */,
|
||||
341F5EEF2A0F886600962D48 /* ForeignFutures.swift */,
|
||||
);
|
||||
path = Foreign;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EF32A0F88AC00962D48 /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EDD2A0F300100962D48 /* Request.swift */,
|
||||
341F5F022A11A2BC00962D48 /* Credential.swift */,
|
||||
341F5EFE2A10955D00962D48 /* OrderRequest.swift */,
|
||||
);
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
341F5EA62A0A80EC00962D48 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EBC2A0A80EC00962D48 /* KissMe.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
341F5EAA2A0A80EC00962D48 /* KissMe */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 341F5EBF2A0A80EC00962D48 /* Build configuration list for PBXNativeTarget "KissMe" */;
|
||||
buildPhases = (
|
||||
341F5EA62A0A80EC00962D48 /* Headers */,
|
||||
341F5EA72A0A80EC00962D48 /* Sources */,
|
||||
341F5EA82A0A80EC00962D48 /* Frameworks */,
|
||||
341F5EA92A0A80EC00962D48 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = KissMe;
|
||||
productName = KissMe;
|
||||
productReference = 341F5EAB2A0A80EC00962D48 /* KissMe.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
341F5EB42A0A80EC00962D48 /* KissMeTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 341F5EC22A0A80EC00962D48 /* Build configuration list for PBXNativeTarget "KissMeTests" */;
|
||||
buildPhases = (
|
||||
341F5EB12A0A80EC00962D48 /* Sources */,
|
||||
341F5EB22A0A80EC00962D48 /* Frameworks */,
|
||||
341F5EB32A0A80EC00962D48 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
341F5EB82A0A80EC00962D48 /* PBXTargetDependency */,
|
||||
);
|
||||
name = KissMeTests;
|
||||
productName = KissMeTests;
|
||||
productReference = 341F5EB52A0A80EC00962D48 /* KissMeTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
341F5EA22A0A80EC00962D48 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1430;
|
||||
TargetAttributes = {
|
||||
341F5EAA2A0A80EC00962D48 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
};
|
||||
341F5EB42A0A80EC00962D48 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 341F5EA52A0A80EC00962D48 /* Build configuration list for PBXProject "KissMe" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 341F5EA12A0A80EC00962D48;
|
||||
productRefGroup = 341F5EAC2A0A80EC00962D48 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
341F5EAA2A0A80EC00962D48 /* KissMe */,
|
||||
341F5EB42A0A80EC00962D48 /* KissMeTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
341F5EA92A0A80EC00962D48 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
341F5EB32A0A80EC00962D48 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
341F5EA72A0A80EC00962D48 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */,
|
||||
341F5F032A11A2BC00962D48 /* Credential.swift in Sources */,
|
||||
341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */,
|
||||
341F5EFD2A10931B00962D48 /* DomesticStockSearch.swift in Sources */,
|
||||
341F5EE52A0F3EF400962D48 /* DomesticStock.swift in Sources */,
|
||||
341F5EF72A0F8B0500962D48 /* DomesticStockResult.swift in Sources */,
|
||||
341F5EF02A0F886600962D48 /* ForeignFutures.swift in Sources */,
|
||||
341F5EEC2A0F883900962D48 /* ForeignStock.swift in Sources */,
|
||||
341F5EFF2A10955D00962D48 /* OrderRequest.swift in Sources */,
|
||||
341F5EE92A0F87FB00962D48 /* DomesticStockPrice.swift in Sources */,
|
||||
341F5EEE2A0F884300962D48 /* ForeignStockPrice.swift in Sources */,
|
||||
341F5EDE2A0F300100962D48 /* Request.swift in Sources */,
|
||||
341F5F012A11155100962D48 /* DomesticStockSearchResult.swift in Sources */,
|
||||
341F5EF22A0F887200962D48 /* DomesticFutures.swift in Sources */,
|
||||
341F5EF92A0F907300962D48 /* DomesticStockPriceResult.swift in Sources */,
|
||||
341F5EE12A0F373B00962D48 /* Login.swift in Sources */,
|
||||
341F5EF52A0F891200962D48 /* KissAccount.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
341F5EB12A0A80EC00962D48 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EBB2A0A80EC00962D48 /* KissMeTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
341F5EB82A0A80EC00962D48 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 341F5EAA2A0A80EC00962D48 /* KissMe */;
|
||||
targetProxy = 341F5EB72A0A80EC00962D48 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
341F5EBD2A0A80EC00962D48 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
341F5EBE2A0A80EC00962D48 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
341F5EC02A0A80EC00962D48 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ened.KissMe;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = auto;
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
341F5EC12A0A80EC00962D48 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ened.KissMe;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = auto;
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
341F5EC32A0A80EC00962D48 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ened.KissMeTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
341F5EC42A0A80EC00962D48 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ened.KissMeTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
341F5EA52A0A80EC00962D48 /* Build configuration list for PBXProject "KissMe" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
341F5EBD2A0A80EC00962D48 /* Debug */,
|
||||
341F5EBE2A0A80EC00962D48 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
341F5EBF2A0A80EC00962D48 /* Build configuration list for PBXNativeTarget "KissMe" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
341F5EC02A0A80EC00962D48 /* Debug */,
|
||||
341F5EC12A0A80EC00962D48 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
341F5EC22A0A80EC00962D48 /* Build configuration list for PBXNativeTarget "KissMeTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
341F5EC32A0A80EC00962D48 /* Debug */,
|
||||
341F5EC42A0A80EC00962D48 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 341F5EA22A0A80EC00962D48 /* Project object */;
|
||||
}
|
||||
7
KissMe.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
KissMe.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
10
KissMe.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
KissMe.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:KissMeConsole/KissMeConsole.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "container:KissMe.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
8
KissMe.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Normal file
8
KissMe.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
71
KissMe/Common/Credential.swift
Normal file
71
KissMe/Common/Credential.swift
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Credential.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/15.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol Credential {
|
||||
var isMock: Bool { get }
|
||||
var accountNo: String { get }
|
||||
var appKey: String { get }
|
||||
var appSecret: String { get }
|
||||
}
|
||||
|
||||
extension String {
|
||||
var digitsOnly: String { filter { ("0"..."9").contains($0) } }
|
||||
}
|
||||
|
||||
|
||||
public struct KissCredential: Credential, Codable {
|
||||
public let isMock: Bool
|
||||
public let accountNo: String
|
||||
public let appKey: String
|
||||
public let appSecret: String
|
||||
|
||||
public init(isMock: Bool, accountNo: String, appKey: String, appSecret: String) throws {
|
||||
let digitAccountNo = accountNo.digitsOnly
|
||||
guard digitAccountNo.count == 10 else {
|
||||
throw GeneralError.invalidAccountNo
|
||||
}
|
||||
|
||||
self.isMock = isMock
|
||||
self.accountNo = digitAccountNo
|
||||
self.appKey = appKey
|
||||
self.appSecret = appSecret
|
||||
}
|
||||
|
||||
public init(jsonUrl: URL) throws {
|
||||
do {
|
||||
let data = try Data(contentsOf: jsonUrl, options: .uncached)
|
||||
let jsonData = try JSONDecoder().decode(KissCredential.self, from: data)
|
||||
try self.init(isMock: jsonData.isMock,
|
||||
accountNo: jsonData.accountNo,
|
||||
appKey: jsonData.appKey,
|
||||
appSecret: jsonData.appSecret)
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
public init(isMock: Bool) throws {
|
||||
let serverFileName = isMock ? "mock-server.json": "real-server.json"
|
||||
let path = "\(FileManager.default.currentDirectoryPath)/\(serverFileName)"
|
||||
let jsonUrl = URL(filePath: path)
|
||||
|
||||
try self.init(jsonUrl: jsonUrl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension AuthRequest {
|
||||
|
||||
public var domain: String {
|
||||
credential.isMock ?
|
||||
"https://openapivts.koreainvestment.com:29443":
|
||||
"https://openapi.koreainvestment.com:9443"
|
||||
}
|
||||
}
|
||||
66
KissMe/Common/OrderRequest.swift
Normal file
66
KissMe/Common/OrderRequest.swift
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// OrderRequest.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/14.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol OrderRequest: TokenRequest {
|
||||
var accountNo: String { get }
|
||||
}
|
||||
|
||||
|
||||
extension OrderRequest {
|
||||
public var accountNo: String {
|
||||
credential.accountNo
|
||||
}
|
||||
|
||||
var accountNo8: String {
|
||||
String(accountNo.prefix(8))
|
||||
}
|
||||
|
||||
var accountNo2: String {
|
||||
String(accountNo.suffix(2))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum OrderType {
|
||||
case buy
|
||||
case sell
|
||||
}
|
||||
|
||||
|
||||
public enum OrderDivision {
|
||||
/// 지정가
|
||||
case limits
|
||||
|
||||
/// 시장가
|
||||
case marketPrice
|
||||
|
||||
var code: String {
|
||||
switch self {
|
||||
case .limits: return "00"
|
||||
case .marketPrice: return "01"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum OrderRevisionType {
|
||||
/// 정정
|
||||
case modify
|
||||
|
||||
/// 취소
|
||||
case cancel
|
||||
|
||||
var code: String {
|
||||
switch self {
|
||||
case .modify: return "01"
|
||||
case .cancel: return "02"
|
||||
}
|
||||
}
|
||||
}
|
||||
160
KissMe/Common/Request.swift
Normal file
160
KissMe/Common/Request.swift
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Request.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public enum Method {
|
||||
case `get`
|
||||
case post
|
||||
}
|
||||
|
||||
extension Method: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .get: return "GET"
|
||||
case .post: return "POST"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum GeneralError: Error {
|
||||
case noServerJsonFile
|
||||
case invalidAccessToken
|
||||
case invalidAccountNo
|
||||
case unsupportedQueryAtMockServer
|
||||
}
|
||||
|
||||
public enum QueryError: Error {
|
||||
case invalidUrl
|
||||
case invalidJson
|
||||
case missingData
|
||||
}
|
||||
|
||||
|
||||
public protocol Request {
|
||||
associatedtype KResult: Decodable
|
||||
|
||||
var isMockAvailable: Bool { get }
|
||||
var domain: String { get }
|
||||
var url: String { get }
|
||||
var userAgent: String { get }
|
||||
|
||||
var method: Method { get }
|
||||
var header: [String: String?] { get }
|
||||
var body: [String: Any] { get }
|
||||
var result: KResult? { get set }
|
||||
var timeout: TimeInterval { get }
|
||||
}
|
||||
|
||||
|
||||
public protocol AuthRequest: Request {
|
||||
var credential: Credential { get }
|
||||
}
|
||||
|
||||
|
||||
public protocol TokenRequest: AuthRequest {
|
||||
var accessToken: String { get }
|
||||
}
|
||||
|
||||
|
||||
extension Request {
|
||||
public var isMockAvailable: Bool { true }
|
||||
|
||||
public var userAgent: String {
|
||||
//"KissMe Agent"
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
|
||||
}
|
||||
|
||||
public var method: Method { .get }
|
||||
public var header: [String: String?] { [:] }
|
||||
}
|
||||
|
||||
|
||||
extension AuthRequest {
|
||||
|
||||
public var timeout: TimeInterval {
|
||||
15
|
||||
}
|
||||
|
||||
var queryUrl: URL? {
|
||||
URL(string: domain + url)
|
||||
}
|
||||
|
||||
func query(completion: @escaping (Result<KResult, Error>) -> Void) {
|
||||
guard let url = queryUrl else {
|
||||
completion(.failure(QueryError.invalidUrl))
|
||||
return
|
||||
}
|
||||
|
||||
if isMockAvailable == false, credential.isMock == true {
|
||||
completion(.failure(GeneralError.unsupportedQueryAtMockServer))
|
||||
return
|
||||
}
|
||||
|
||||
let jsonBody: Data?
|
||||
do {
|
||||
jsonBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
|
||||
} catch {
|
||||
completion(.failure(QueryError.invalidJson))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeout)
|
||||
|
||||
request.httpMethod = String(describing: method)
|
||||
|
||||
switch method {
|
||||
case .post:
|
||||
request.httpBody = jsonBody
|
||||
request.setValue("\(jsonBody?.count ?? 0)", forHTTPHeaderField: "Content-Length")
|
||||
|
||||
case .get:
|
||||
var queryItems = [URLQueryItem]()
|
||||
for item in body {
|
||||
if let value = item.value as? String {
|
||||
queryItems.append(URLQueryItem(name: item.key, value: value))
|
||||
}
|
||||
}
|
||||
request.url?.append(queryItems: queryItems)
|
||||
}
|
||||
|
||||
request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
||||
request.setValue("JSON", forHTTPHeaderField: "Format")
|
||||
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
|
||||
|
||||
for field in header {
|
||||
request.setValue(field.value, forHTTPHeaderField: field.key)
|
||||
}
|
||||
|
||||
URLSession.shared.dataTask(with: request) { (data, response, error) in
|
||||
if let error = error {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
completion(.failure(QueryError.missingData))
|
||||
return
|
||||
}
|
||||
|
||||
let stringData = String(data: data, encoding: .utf8) ?? ""
|
||||
print(stringData)
|
||||
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
decoder.keyDecodingStrategy = .useDefaultKeys
|
||||
|
||||
let result = try decoder.decode(KResult.self, from: data)
|
||||
completion(.success(result))
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
13
KissMe/Domestic/DomesticFutures.swift
Normal file
13
KissMe/Domestic/DomesticFutures.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// DomesticFutures.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
extension Domestic {
|
||||
|
||||
}
|
||||
330
KissMe/Domestic/DomesticStock.swift
Normal file
330
KissMe/Domestic/DomesticStock.swift
Normal file
@@ -0,0 +1,330 @@
|
||||
//
|
||||
// DomesticStock.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public struct Domestic {
|
||||
|
||||
/// 국내주식주문 - 주식주문(현금)
|
||||
///
|
||||
public struct StockOrderRequest: OrderRequest {
|
||||
public typealias KResult = OrderResult
|
||||
|
||||
public var url: String { "/uapi/domestic-stock/v1/trading/order-cash" }
|
||||
public var method: Method { .post }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"CANO": accountNo8,
|
||||
"ACNT_PRDT_CD": accountNo2,
|
||||
"PDNO": productNo,
|
||||
"ORD_DVSN": orderDivision.code,
|
||||
"ORD_QTY": orderQuantity,
|
||||
"ORD_UNPR": String(orderPrice),
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
if credential.isMock {
|
||||
switch orderType {
|
||||
case .buy: return "VTTC0802U"
|
||||
case .sell: return "VTTC0801U"
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch orderType {
|
||||
case .buy: return "TTTC0802U"
|
||||
case .sell: return "TTTC0801U"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let productNo: String
|
||||
|
||||
let orderType: OrderType
|
||||
let orderDivision: OrderDivision
|
||||
let orderQuantity: Int
|
||||
let orderPrice: Int
|
||||
|
||||
public init(credential: Credential, accessToken: String, contract: Contract) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.productNo = contract.productNo
|
||||
self.orderType = contract.orderType
|
||||
self.orderDivision = contract.orderDivision
|
||||
self.orderQuantity = contract.orderQuantity
|
||||
self.orderPrice = contract.orderPrice
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 국내주식주문 - 주식주문(정정취소)[v1_국내주식-003]
|
||||
///
|
||||
public struct StockOrderRevisionRequest: OrderRequest {
|
||||
public typealias KResult = OrderRevisionResult
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/trading/order-rvsecncl"
|
||||
}
|
||||
public var method: Method { .post }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"CANO": accountNo8,
|
||||
"ACNT_PRDT_CD": accountNo2,
|
||||
"KRX_FWDG_ORD_ORGNO": orderOrganizationNo,
|
||||
"ORGN_ODNO": orderNo,
|
||||
"ORD_DVSN": orderDivision.code,
|
||||
"RVSE_CNCL_DVSN_CD": orderRevisionType.code,
|
||||
"ORD_QTY": String(orderQuantity),
|
||||
"ORD_UNPR": String(orderPrice),
|
||||
"QTY_ALL_ORD_YN": isAllQuantity ? "Y": "N"
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
if credential.isMock {
|
||||
return "VTTC0803U"
|
||||
}
|
||||
else {
|
||||
return "TTTC0803U"
|
||||
}
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let productNo: String
|
||||
|
||||
let orderOrganizationNo: String
|
||||
let orderNo: String
|
||||
let orderDivision: OrderDivision
|
||||
let orderRevisionType: OrderRevisionType
|
||||
let orderQuantity: Int
|
||||
let orderPrice: Int
|
||||
let isAllQuantity: Bool
|
||||
|
||||
public init(credential: Credential, accessToken: String, productNo: String, orderOrganizationNo: String, orderNo: String, orderDivision: OrderDivision, orderRevisionType: OrderRevisionType, orderQuantity: Int = 0, orderPrice: Int) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.productNo = productNo
|
||||
self.orderOrganizationNo = orderOrganizationNo
|
||||
self.orderNo = orderNo
|
||||
self.orderDivision = orderDivision
|
||||
self.orderRevisionType = orderRevisionType
|
||||
self.orderQuantity = orderQuantity
|
||||
self.orderPrice = orderPrice
|
||||
self.isAllQuantity = (orderQuantity == 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 국내주식주문 - 주식잔고조회[v1_국내주식-006]
|
||||
///
|
||||
public struct StockBalanceRequest: OrderRequest {
|
||||
public typealias KResult = String
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/trading/inquire-balance"
|
||||
}
|
||||
public var method: Method { .get }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"CANO": accountNo8,
|
||||
"ACNT_PRDT_CD": accountNo2,
|
||||
"AFHR_FLPR_YN": "N",
|
||||
"OFL_YN": " ",
|
||||
"INQR_DVSN": "02",
|
||||
"UNPR_DVSN": "01",
|
||||
"FUND_STTL_ICLD_YN": "N",
|
||||
"FNCG_AMT_AUTO_RDPT_YN": "N",
|
||||
"PRCS_DVSN": "01",
|
||||
"CTX_AREA_FK100": " ",
|
||||
"CTX_AREA_NK100": " ",
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
if credential.isMock {
|
||||
return "VTTC0803U"
|
||||
}
|
||||
else {
|
||||
return "TTTC0803U"
|
||||
}
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
|
||||
public init(credential: Credential, accessToken: String) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 국내주식주문 - 매수가능조회[v1_국내주식-007]
|
||||
///
|
||||
public struct StockPossibleOrderRequest: OrderRequest {
|
||||
public typealias KResult = OrderPossibleResult
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/trading/inquire-psbl-order"
|
||||
}
|
||||
public var method: Method { .get }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"CANO": accountNo8,
|
||||
"ACNT_PRDT_CD": accountNo2,
|
||||
"PDNO": productNo,
|
||||
"ORD_UNPR": String(orderPrice),
|
||||
"ORD_DVSN": orderDivision.code,
|
||||
"CMA_EVLU_AMT_ICLD_YN": "",
|
||||
"OVRS_ICLD_YN": "",
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
if credential.isMock {
|
||||
return "VTTC8908R"
|
||||
}
|
||||
else {
|
||||
return "TTTC8908R"
|
||||
}
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let productNo: String
|
||||
|
||||
let orderDivision: OrderDivision
|
||||
let orderPrice: Int
|
||||
|
||||
public init(credential: Credential, accessToken: String, productNo: String, orderDivision: OrderDivision, orderPrice: Int) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.productNo = productNo
|
||||
self.orderDivision = orderDivision
|
||||
self.orderPrice = orderPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Contract {
|
||||
public let productNo: String
|
||||
public let orderType: OrderType
|
||||
public let orderDivision: OrderDivision
|
||||
public let orderQuantity: Int
|
||||
public let orderPrice: Int
|
||||
}
|
||||
|
||||
|
||||
// MARK: Stock Order
|
||||
extension KissAccount {
|
||||
|
||||
public func orderStock(contract: Contract, completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
let request = Domestic.StockOrderRequest(credential: credential, accessToken: accessToken, contract: contract)
|
||||
request.query { result in
|
||||
switch result {
|
||||
case .success(let result):
|
||||
completion(.success(true))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func cancelOrder(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
|
||||
|
||||
public func changeOrder(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
|
||||
|
||||
public func getStockBalance(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
|
||||
|
||||
public func canOrderStock(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
}
|
||||
128
KissMe/Domestic/DomesticStockPrice.swift
Normal file
128
KissMe/Domestic/DomesticStockPrice.swift
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// DomesticStockPrice.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
extension Domestic {
|
||||
|
||||
/// 국내주식시세 - 주식현재가 시세[v1_국내주식-008]
|
||||
///
|
||||
public struct StockCurrentPriceRequest: TokenRequest {
|
||||
public typealias KResult = CurrentPriceResult
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/quotations/inquire-price"
|
||||
}
|
||||
public var method: Method { .get }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"FID_COND_MRKT_DIV_CODE": "J",
|
||||
"FID_INPUT_ISCD": productNo,
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
"FHKST01010100"
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let productNo: String
|
||||
|
||||
public init(credential: Credential, accessToken: String, productNo: String) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.productNo = productNo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 국내주식시세 - 주식당일분봉조회[v1_국내주식-022]
|
||||
///
|
||||
public struct StockTodayMinutePriceRequest: TokenRequest {
|
||||
public typealias KResult = MinutePriceResult
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/quotations/inquire-time-itemchartprice"
|
||||
}
|
||||
public var method: Method { .get }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
"custtype": CustomerType.personal.rawValue,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"FID_ETC_CLS_CODE": "",
|
||||
"FID_COND_MRKT_DIV_CODE": "J",
|
||||
"FID_INPUT_ISCD": productNo,
|
||||
"FID_INPUT_HOUR_1": startTime,
|
||||
"FID_PW_DATA_INCU_YN": "N",
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
"FHKST03010200"
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let productNo: String
|
||||
let startTime: String // HHMMSS
|
||||
|
||||
public init(credential: Credential, accessToken: String, productNo: String, startTime: String) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.productNo = productNo
|
||||
self.startTime = startTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Stock Price
|
||||
extension KissAccount {
|
||||
|
||||
|
||||
public func getCurrentPrice(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
|
||||
|
||||
public func getMinutePrice(completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let accessToken = accessToken else {
|
||||
completion(.failure(GeneralError.invalidAccessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: work
|
||||
}
|
||||
}
|
||||
502
KissMe/Domestic/DomesticStockPriceResult.swift
Normal file
502
KissMe/Domestic/DomesticStockPriceResult.swift
Normal file
@@ -0,0 +1,502 @@
|
||||
//
|
||||
// DomesticStockPriceResult.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public enum YesNo: String, Codable {
|
||||
case yes = "Y"
|
||||
case no = "N"
|
||||
}
|
||||
|
||||
|
||||
/// 보증금 비율 구분
|
||||
public enum MarginalRateClass: String, Codable {
|
||||
/// 20%, 30%, 40%
|
||||
case _40 = "40"
|
||||
/// 50%
|
||||
case _50 = "50"
|
||||
/// 60%
|
||||
case _60 = "60"
|
||||
}
|
||||
|
||||
|
||||
/// 시장경고코드
|
||||
public enum MarketWarning: String, Codable {
|
||||
/// 없음
|
||||
case none = "00"
|
||||
/// 투자주의
|
||||
case investmentCaution = "01"
|
||||
/// 투자경고
|
||||
case investmentWarning = "02"
|
||||
/// 투자위험
|
||||
case investmentDanger = "03"
|
||||
}
|
||||
|
||||
|
||||
public struct CurrentPriceResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output: [OutputDetail]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg1"
|
||||
case output
|
||||
}
|
||||
|
||||
/// 종목 상태 구분
|
||||
public enum StateClass: String, Codable {
|
||||
/// 그외
|
||||
case etc = "00"
|
||||
/// 관리종목
|
||||
case underAdmin = "51"
|
||||
/// 투자의견
|
||||
case investmentOption = "52"
|
||||
/// 투자경고
|
||||
case investmentWarning = "53"
|
||||
/// 투자주의
|
||||
case investmentCaution = "54"
|
||||
/// 신용가능
|
||||
case creditWorthy = "55"
|
||||
/// 증거금 100%
|
||||
case depositAll = "57"
|
||||
/// 거래정지
|
||||
case tradingHalt = "58"
|
||||
/// 단기과열
|
||||
case shortTermOverheating = "59"
|
||||
}
|
||||
|
||||
public struct OutputDetail: Codable {
|
||||
/// 종목 상태 구분 코드
|
||||
public let itemStateCode: StateClass
|
||||
|
||||
/// 증거금 비율
|
||||
public let marginalRate: String
|
||||
|
||||
/// 대표 시장 한글 명
|
||||
public let koreanMarketName: String
|
||||
|
||||
/// 신 고가 저가 구분 코드
|
||||
public let newHighLowPriceClassCode: String
|
||||
|
||||
/// 업종 한글 종목명
|
||||
public let koreanBusinessTypeName: String
|
||||
|
||||
/// 임시 정지 여부
|
||||
public let temporaryStopped: YesNo
|
||||
|
||||
/// 시가 범위 연장 여부
|
||||
public let marketPriceRangeExtended: YesNo
|
||||
|
||||
/// 종가 범위 연장 여부
|
||||
public let closingPriceRangeExtended: YesNo
|
||||
|
||||
/// 신용 가능 여부
|
||||
public let creditAllowable: YesNo
|
||||
|
||||
/// 보증금 비율 구분 코드
|
||||
public let marginalRateClassCode: MarginalRateClass
|
||||
|
||||
/// ELW 발행 여부
|
||||
public let elwPublished: YesNo
|
||||
|
||||
/// 주식 현재가
|
||||
public let currentStockPrice: String
|
||||
|
||||
/// 전일 대비
|
||||
public let previousDayVariableRatio: String
|
||||
|
||||
/// 전일 대비 부호
|
||||
public let previousDayVariableRatioSign: String
|
||||
|
||||
/// 전일 대비율
|
||||
public let previousDayDiffRatio: String
|
||||
|
||||
/// 누적 거래 대금
|
||||
public let accumulatedTradingAmount: String
|
||||
|
||||
/// 누적 거래량
|
||||
public let accumulatedVolume: String
|
||||
|
||||
/// 전일 대비 거래량 비율
|
||||
public let previousDayDiffVolumeRatio: String
|
||||
|
||||
/// 주식 시가
|
||||
public let stockPrice: String
|
||||
|
||||
/// 주식 최고가
|
||||
public let highestStockPrice: String
|
||||
|
||||
/// 주식 최저가
|
||||
public let lowestStockPrice: String
|
||||
|
||||
/// 주식 상한가
|
||||
public let maximumStockPrice: String
|
||||
|
||||
/// 주식 하한가
|
||||
public let minimumStockPrice: String
|
||||
|
||||
/// 주식 기준가
|
||||
public let standardStockPrice: String
|
||||
|
||||
/// 가중 평균 주식 가격
|
||||
public let weightedAverageStockPrice: String
|
||||
|
||||
/// HTS 외국인 소진율
|
||||
public let htsForeignRunoutRate: String
|
||||
|
||||
/// 외국인 순매수 수량
|
||||
public let foreignNetBuyingQuantity: String
|
||||
|
||||
/// 프로그램매매 순매수 수량
|
||||
public let programTradeNetBuyingQuantity: String
|
||||
|
||||
/// 피벗 2차 디저항 가격
|
||||
public let pivotSecondDResistancePrice: String
|
||||
|
||||
/// 피벗 1차 디저항 가격
|
||||
public let pivotFirstDResistancePrice: String
|
||||
|
||||
/// 피벗 포인트 값
|
||||
public let pivotPointValue: String
|
||||
|
||||
/// 피벗 1차 디지지 가격
|
||||
public let pivotFirstDSupportPrice: String
|
||||
|
||||
/// 피벗 2차 디지지 가격
|
||||
public let pivotSecondDSupportPrice: String
|
||||
|
||||
/// 디저항 값
|
||||
public let dResistanceValue: String
|
||||
|
||||
/// 디지지 값
|
||||
public let dSupportValue: String
|
||||
|
||||
/// 자본금
|
||||
public let capital: String
|
||||
|
||||
/// 제한 폭 가격
|
||||
public let limitWidthPrice: String
|
||||
|
||||
/// 주식 액면가
|
||||
public let stockFacePrice: String
|
||||
|
||||
/// 주식 대용가
|
||||
public let stockSubstitudePrice: String
|
||||
|
||||
/// 호가단위
|
||||
public let askingPriceUnit: String
|
||||
|
||||
/// HTS 매매 수량 단위 값
|
||||
public let htsDealQuantityUnit: String
|
||||
|
||||
/// 상장 주수
|
||||
public let listedStockCount: String
|
||||
|
||||
/// HTS 시가총액
|
||||
public let htsTotalMarketValue: String
|
||||
|
||||
/// PER
|
||||
public let per: String
|
||||
|
||||
/// PBR
|
||||
public let pbr: String
|
||||
|
||||
/// 결산 월
|
||||
public let settlingMonth: String
|
||||
|
||||
/// 거래량 회전율
|
||||
public let volumeTurnoverRate: String
|
||||
|
||||
/// EPS
|
||||
public let eps: String
|
||||
|
||||
/// BPS
|
||||
public let bps: String
|
||||
|
||||
/// 250일 최고가
|
||||
public let day250HighestPrice: String
|
||||
|
||||
/// 250일 최고가 일자
|
||||
public let day250HighestPriceDate: String
|
||||
|
||||
/// 250일 최고가 대비 현재가 비율
|
||||
public let day250HighestPriceDiffRatio: String
|
||||
|
||||
/// 250일 최저가
|
||||
public let day250LowestPrice: String
|
||||
|
||||
/// 250일 최저가 일자
|
||||
public let day250LowestPriceDate: String
|
||||
|
||||
/// 250일 최저가 대비 현재가 비율
|
||||
public let day250LowestPriceDiffRatio: String
|
||||
|
||||
/// 주식 연중 최고가
|
||||
public let annualHighestPrice: String
|
||||
|
||||
/// 연중 최고가 대비 현재가 비율
|
||||
public let annualHighestPriceDiffRatio: String
|
||||
|
||||
/// 연중 최고가 일자
|
||||
public let annualHighestPriceDate: String
|
||||
|
||||
/// 주식 연중 최저가
|
||||
public let annualLowestPrice: String
|
||||
|
||||
/// 연중 최저가 대비 현재가 비율
|
||||
public let annualLowestPriceDiffRatio: String
|
||||
|
||||
/// 연중 최저가 일자
|
||||
public let annualLowestPriceDate: String
|
||||
|
||||
/// 52주일 최고가
|
||||
public let week52HighestPrice: String
|
||||
|
||||
/// 52주일 최고가 대비 현재가 대비
|
||||
public let week52HighestPriceDiffRatio: String
|
||||
|
||||
/// 52주일 최고가 일자
|
||||
public let week52HighestPriceDate: String
|
||||
|
||||
/// 52주일 최저가
|
||||
public let week52LowestPrice: String
|
||||
|
||||
/// 52주일 최저가 대비 현재가 대비
|
||||
public let week52LowestPriceDiffRatio: String
|
||||
|
||||
/// 52주일 최저가 일자
|
||||
public let week52LowestPriceDate: String
|
||||
|
||||
/// 전체 융자 잔고 비율
|
||||
public let totalOutstandingloanRate: String
|
||||
|
||||
/// 공매도가능여부
|
||||
public let shortSellingAllowable: YesNo
|
||||
|
||||
/// 주식 단축 종목코드
|
||||
public let shortProductCode: String
|
||||
|
||||
/// 액면가 통화명
|
||||
public let facePriceCurrency: String
|
||||
|
||||
/// 자본금 통화명
|
||||
public let capitalCurrency: String
|
||||
|
||||
/// 접근도
|
||||
public let approachRate: String
|
||||
|
||||
/// 외국인 보유 수량
|
||||
public let foreignHoldQuantity: String
|
||||
|
||||
/// VI적용구분코드
|
||||
public let viClassCode: String
|
||||
|
||||
/// 시간외단일가VI적용구분코드
|
||||
public let viClassCodeForOvertimeMarketPrice: String
|
||||
|
||||
/// 최종 공매도 체결 수량
|
||||
public let lastShortSellingConclusionQuantity: String
|
||||
|
||||
/// 투자유의여부
|
||||
public let investmentCareful: YesNo
|
||||
|
||||
/// 시장경고코드
|
||||
public let marketWarningCode: MarketWarning
|
||||
|
||||
/// 단기과열여부
|
||||
public let shortOverheated: YesNo
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case itemStateCode = "iscd_stat_cls_code"
|
||||
case marginalRate = "marg_rate"
|
||||
case koreanMarketName = "rprs_mrkt_kor_name"
|
||||
case newHighLowPriceClassCode = "new_hgpr_lwpr_cls_code"
|
||||
|
||||
case koreanBusinessTypeName = "bstp_kor_isnm"
|
||||
case temporaryStopped = "temp_stop_yn"
|
||||
case marketPriceRangeExtended = "oprc_rang_cont_yn"
|
||||
case closingPriceRangeExtended = "clpr_rang_cont_yn"
|
||||
case creditAllowable = "crdt_able_yn"
|
||||
case marginalRateClassCode = "grmn_rate_cls_code"
|
||||
case elwPublished = "elw_pblc_yn"
|
||||
|
||||
case currentStockPrice = "stck_prpr"
|
||||
case previousDayVariableRatio = "prdy_vrss"
|
||||
case previousDayVariableRatioSign = "prdy_vrss_sign"
|
||||
case previousDayDiffRatio = "prdy_ctrt"
|
||||
case accumulatedTradingAmount = "acml_tr_pbmn"
|
||||
case accumulatedVolume = "acml_vol"
|
||||
case previousDayDiffVolumeRatio = "prdy_vrss_vol_rate"
|
||||
|
||||
case stockPrice = "stck_oprc"
|
||||
case highestStockPrice = "stck_hgpr"
|
||||
case lowestStockPrice = "stck_lwpr"
|
||||
case maximumStockPrice = "stck_mxpr"
|
||||
case minimumStockPrice = "stck_llam"
|
||||
case standardStockPrice = "stck_sdpr"
|
||||
case weightedAverageStockPrice = "wghn_avrg_stck_prc"
|
||||
|
||||
case htsForeignRunoutRate = "hts_frgn_ehrt"
|
||||
case foreignNetBuyingQuantity = "frgn_ntby_qty"
|
||||
case programTradeNetBuyingQuantity = "pgtr_ntby_qty"
|
||||
case pivotSecondDResistancePrice = "pvt_scnd_dmrs_prc"
|
||||
case pivotFirstDResistancePrice = "pvt_frst_dmrs_prc"
|
||||
case pivotPointValue = "pvt_pont_val"
|
||||
case pivotFirstDSupportPrice = "pvt_frst_dmsp_prc"
|
||||
case pivotSecondDSupportPrice = "pvt_scnd_dmsp_prc"
|
||||
case dResistanceValue = "dmrs_val"
|
||||
case dSupportValue = "dmsp_val"
|
||||
|
||||
case capital = "cpfn"
|
||||
case limitWidthPrice = "rstc_wdth_prc"
|
||||
case stockFacePrice = "stck_fcam"
|
||||
case stockSubstitudePrice = "stck_sspr"
|
||||
case askingPriceUnit = "aspr_unit"
|
||||
case htsDealQuantityUnit = "hts_deal_qty_unit_val"
|
||||
case listedStockCount = "lstn_stcn"
|
||||
case htsTotalMarketValue = "hts_avls"
|
||||
|
||||
case per
|
||||
case pbr
|
||||
case settlingMonth = "stac_month"
|
||||
case volumeTurnoverRate = "vol_tnrt"
|
||||
case eps
|
||||
case bps
|
||||
|
||||
case day250HighestPrice = "d250_hgpr"
|
||||
case day250HighestPriceDate = "d250_hgpr_date"
|
||||
case day250HighestPriceDiffRatio = "d250_hgpr_vrss_prpr_rate"
|
||||
case day250LowestPrice = "d250_lwpr"
|
||||
case day250LowestPriceDate = "d250_lwpr_date"
|
||||
case day250LowestPriceDiffRatio = "d250_lwpr_vrss_prpr_rate"
|
||||
|
||||
case annualHighestPrice = "stck_dryy_hgpr"
|
||||
case annualHighestPriceDiffRatio = "dryy_hgpr_vrss_prpr_rate"
|
||||
case annualHighestPriceDate = "dryy_hgpr_date"
|
||||
case annualLowestPrice = "stck_dryy_lwpr"
|
||||
case annualLowestPriceDiffRatio = "dryy_lwpr_vrss_prpr_rate"
|
||||
case annualLowestPriceDate = "dryy_lwpr_date"
|
||||
|
||||
case week52HighestPrice = "w52_hgpr"
|
||||
case week52HighestPriceDiffRatio = "w52_hgpr_vrss_prpr_ctrt"
|
||||
case week52HighestPriceDate = "w52_hgpr_date"
|
||||
case week52LowestPrice = "w52_lwpr"
|
||||
case week52LowestPriceDiffRatio = "w52_lwpr_vrss_prpr_ctrt"
|
||||
case week52LowestPriceDate = "w52_lwpr_date"
|
||||
|
||||
case totalOutstandingloanRate = "whol_loan_rmnd_rate"
|
||||
case shortSellingAllowable = "ssts_yn"
|
||||
case shortProductCode = "stck_shrn_iscd"
|
||||
case facePriceCurrency = "fcam_cnnm"
|
||||
case capitalCurrency = "cpfn_cnnm"
|
||||
case approachRate = "apprch_rate"
|
||||
|
||||
case foreignHoldQuantity = "frgn_hldn_qty"
|
||||
case viClassCode = "vi_cls_code"
|
||||
case viClassCodeForOvertimeMarketPrice = "ovtm_vi_cls_code"
|
||||
case lastShortSellingConclusionQuantity = "last_ssts_cntg_qty"
|
||||
case investmentCareful = "invt_caful_yn"
|
||||
case marketWarningCode = "mrkt_warn_cls_code"
|
||||
case shortOverheated = "short_over_yn"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct MinutePriceResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output1: [OutputSummary]?
|
||||
public let output2: [OutputPrice]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg1"
|
||||
case output1
|
||||
case output2
|
||||
}
|
||||
|
||||
public struct OutputSummary: Codable {
|
||||
/// 전일 대비
|
||||
public let previousDayVariableRatio: String
|
||||
|
||||
/// 전일 대비 부호
|
||||
public let previousDayVariableRatioSign: String
|
||||
|
||||
/// 전일 대비율
|
||||
public let previousDayDiffRatio: String
|
||||
|
||||
/// 주식 전일 종가
|
||||
public let previousDayStockClosingPrice: String
|
||||
|
||||
/// 누적 거래량
|
||||
public let accumulatedVolume: String
|
||||
|
||||
/// 누적 거래 대금
|
||||
public let accumulatedTradingAmount: String
|
||||
|
||||
/// HTS 한글 종목명
|
||||
public let htsProductName: String
|
||||
|
||||
/// 주식 현재가
|
||||
public let currentStockPrice: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case previousDayVariableRatio = "prdy_vrss"
|
||||
case previousDayVariableRatioSign = "prdy_vrss_sign"
|
||||
case previousDayDiffRatio = "prdy_ctrt"
|
||||
case previousDayStockClosingPrice = "stck_prdy_clpr"
|
||||
case accumulatedVolume = "acml_vol"
|
||||
case accumulatedTradingAmount = "acml_tr_pbmn"
|
||||
case htsProductName = "hts_kor_isnm"
|
||||
case currentStockPrice = "stck_prpr"
|
||||
}
|
||||
}
|
||||
|
||||
public struct OutputPrice: Codable {
|
||||
/// 주식 영업 일자
|
||||
public let stockBusinessDate: String
|
||||
|
||||
/// 주식 체결 시간
|
||||
public let stockConclusionTime: String
|
||||
|
||||
/// 누적 거래 대금
|
||||
public let accumulatedTradingAmount: String
|
||||
|
||||
/// 주식 현재가
|
||||
public let currentStockPrice: String
|
||||
|
||||
/// 주식 시가2
|
||||
public let secondStockPrice: String
|
||||
|
||||
/// 주식 최고가
|
||||
public let highestStockPrice: String
|
||||
|
||||
/// 주식 최저가
|
||||
public let lowestStockPrice: String
|
||||
|
||||
/// 체결 거래량
|
||||
public let conclusionVolume: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case stockBusinessDate = "stck_bsop_date"
|
||||
case stockConclusionTime = "stck_cntg_hour"
|
||||
case accumulatedTradingAmount = "acml_tr_pbmn"
|
||||
case currentStockPrice = "stck_prpr"
|
||||
case secondStockPrice = "stck_oprc"
|
||||
case highestStockPrice = "stck_hgpr"
|
||||
case lowestStockPrice = "stck_lwpr"
|
||||
case conclusionVolume = "cntg_vol"
|
||||
}
|
||||
}
|
||||
}
|
||||
136
KissMe/Domestic/DomesticStockResult.swift
Normal file
136
KissMe/Domestic/DomesticStockResult.swift
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// DomesticStockResult.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public enum CustomerType: String {
|
||||
case corporation = "B"
|
||||
case personal = "P"
|
||||
}
|
||||
|
||||
|
||||
public struct OrderResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output: [OutputDetail]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg"
|
||||
case output
|
||||
}
|
||||
|
||||
public struct OutputDetail: Codable {
|
||||
public let orderOrganizationNo: String
|
||||
public let orderNo: String
|
||||
public let orderTime: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case orderOrganizationNo = "KRX_FWDG_ORD_ORGNO"
|
||||
case orderNo = "ODNO"
|
||||
case orderTime = "ORD_TMD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct OrderRevisionResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output: [OutputDetail]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg1"
|
||||
case output
|
||||
}
|
||||
|
||||
public struct OutputDetail: Codable {
|
||||
public let orderOrganizationNo: String
|
||||
public let orderNo: String
|
||||
public let orderTime: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case orderOrganizationNo = "KRX_FWDG_ORD_ORGNO"
|
||||
case orderNo = "ODNO"
|
||||
case orderTime = "ORD_TMD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct OrderPossibleResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output: [OutputPossibleDetail]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg1"
|
||||
case output
|
||||
}
|
||||
|
||||
public struct OutputPossibleDetail: Codable {
|
||||
/// 주문가능현금
|
||||
public let orderPossibleCash: String
|
||||
|
||||
/// 주문가능대용
|
||||
public let orderPossibleSubstitute: String
|
||||
|
||||
/// 재사용가능금액
|
||||
public let reusePossibleAmount: String
|
||||
|
||||
/// 펀드환매대금
|
||||
public let fundRepurchaseChanges: String
|
||||
|
||||
/// 가능수량계산단가
|
||||
public let possibleQuantityCalcPrice: String
|
||||
|
||||
/// 미수없는매수금액
|
||||
public let nonrechargeableBuyAmount: String
|
||||
|
||||
/// 미수없는매수수량
|
||||
public let nonrechargeableBuyQuantity: String
|
||||
|
||||
/// 최대매수금액
|
||||
public let maxBuyAmount: String
|
||||
|
||||
/// 최대매수수량
|
||||
public let maxBuyQuantity: String
|
||||
|
||||
/// CMA평가금액
|
||||
public let cmaEvaluationAmount: String
|
||||
|
||||
/// 해외재사용금액원화
|
||||
public let overseasReuseAmountWon: String
|
||||
|
||||
/// 주문가능외화금액원화
|
||||
public let orderPossibleForeignCurrencyAmountWon: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case orderPossibleCash = "ord_psbl_cash"
|
||||
case orderPossibleSubstitute = "ord_psbl_sbst"
|
||||
case reusePossibleAmount = "ruse_psbl_amt"
|
||||
case fundRepurchaseChanges = "fund_rpch_chgs"
|
||||
case possibleQuantityCalcPrice = "psbl_qty_calc_unpr"
|
||||
case nonrechargeableBuyAmount = "nrcvb_buy_amt"
|
||||
case nonrechargeableBuyQuantity = "nrcvb_buy_qty"
|
||||
case maxBuyAmount = "max_buy_amt"
|
||||
case maxBuyQuantity = "max_buy_qty"
|
||||
case cmaEvaluationAmount = "cma_evlu_amt"
|
||||
case overseasReuseAmountWon = "ovrs_re_use_amt_wcrc"
|
||||
case orderPossibleForeignCurrencyAmountWon = "ord_psbl_frcr_amt_wcrc"
|
||||
}
|
||||
}
|
||||
}
|
||||
117
KissMe/Domestic/DomesticStockSearch.swift
Normal file
117
KissMe/Domestic/DomesticStockSearch.swift
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// DomesticStockSearch.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/14.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public enum DivisionClassCode: String {
|
||||
/// 전체
|
||||
case all = "0"
|
||||
/// 보통주
|
||||
case equity = "1"
|
||||
/// 우선주
|
||||
case preferredStock = "2"
|
||||
}
|
||||
|
||||
|
||||
public enum BelongClassCode: String {
|
||||
/// 평균거래량
|
||||
case averageVolume = "0"
|
||||
/// 거래증가율
|
||||
case volumeIncreaseRate = "1"
|
||||
/// 평균거래회전율
|
||||
case averageVolumeTurnoverRate = "2"
|
||||
/// 거래금액순
|
||||
case transactionValue = "3"
|
||||
/// 평균거래금액회전율
|
||||
case averageTransactionValueTurnoverRate = "4"
|
||||
}
|
||||
|
||||
|
||||
extension Domestic {
|
||||
|
||||
/// 국내주식시세 - 거래량순위[v1_국내주식-047]
|
||||
///
|
||||
public struct StockVolumeRankRequest: TokenRequest {
|
||||
public typealias KResult = VolumeRankResult
|
||||
|
||||
public var isMockAvailable: Bool { false }
|
||||
|
||||
public var url: String {
|
||||
"/uapi/domestic-stock/v1/quotations/volume-rank"
|
||||
}
|
||||
public var method: Method { .get }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"authorization": "Bearer \(accessToken)",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"tr_id": trId,
|
||||
"custtype": CustomerType.personal.rawValue,
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"FID_COND_MRKT_DIV_CODE": "J",
|
||||
"FID_COND_SCR_DIV_CODE": "20171",
|
||||
"FID_INPUT_ISCD": "0000", // TODO: 기타(업종코드)
|
||||
"FID_DIV_CLS_CODE": divisionClass.rawValue,
|
||||
"FID_BLNG_CLS_CODE": belongClass.rawValue,
|
||||
"FID_TRGT_CLS_CODE": "000000000",
|
||||
"FID_TRGT_EXLS_CLS_CODE": "000000",
|
||||
"FID_INPUT_PRICE_1": "",
|
||||
"FID_INPUT_PRICE_2": "1000000",
|
||||
"FID_VOL_CNT": "",
|
||||
"FID_INPUT_DATE_1": "",
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
|
||||
private var trId: String {
|
||||
"FHPST01710000"
|
||||
}
|
||||
|
||||
public let accessToken: String
|
||||
let divisionClass: DivisionClassCode
|
||||
let belongClass: BelongClassCode
|
||||
|
||||
public init(credential: Credential, accessToken: String, divisionClass: DivisionClassCode, belongClass: BelongClassCode) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
self.divisionClass = divisionClass
|
||||
self.belongClass = belongClass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Stock Search
|
||||
extension KissAccount {
|
||||
|
||||
public func getVolumeRanking(divisionClass: DivisionClassCode, belongClass: BelongClassCode) async throws -> VolumeRankResult {
|
||||
|
||||
return try await withUnsafeThrowingContinuation { continuation in
|
||||
guard let accessToken = accessToken else {
|
||||
continuation.resume(throwing: GeneralError.invalidAccessToken)
|
||||
return
|
||||
}
|
||||
|
||||
let request = Domestic.StockVolumeRankRequest(credential: credential, accessToken: accessToken, divisionClass: divisionClass, belongClass: belongClass)
|
||||
request.query { result in
|
||||
switch result {
|
||||
case .success(let result):
|
||||
continuation.resume(returning: result)
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
KissMe/Domestic/DomesticStockSearchResult.swift
Normal file
106
KissMe/Domestic/DomesticStockSearchResult.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// DomesticStockSearchResult.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/14.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public struct VolumeRankResult: Codable {
|
||||
public let resultCode: String
|
||||
public let messageCode: String
|
||||
public let message: String
|
||||
public let output1: [OutputDetail]?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case resultCode = "rt_cd"
|
||||
case messageCode = "msg_cd"
|
||||
case message = "msg1"
|
||||
case output1 = "Output1"
|
||||
}
|
||||
|
||||
public struct OutputDetail: Codable {
|
||||
/// HTS 한글 종목명
|
||||
public let htsProductName: String
|
||||
|
||||
/// 유가증권 단축 종목코드
|
||||
public let shortProductNo: String
|
||||
|
||||
/// 데이터 순위
|
||||
public let dataRank: String
|
||||
|
||||
/// 주식 현재가
|
||||
public let currentStockPrice: String
|
||||
|
||||
/// 전일 대비 부호
|
||||
public let previousDayVariableRatioSign: String
|
||||
|
||||
/// 전일 대비
|
||||
public let previousDayVariableRatio: String
|
||||
|
||||
/// 전일 대비율
|
||||
public let previousDayDiffRatio: String
|
||||
|
||||
/// 누적 거래량
|
||||
public let accumulatedVolume: String
|
||||
|
||||
/// 전일 거래량
|
||||
public let previousDayVolume: String
|
||||
|
||||
/// 상장 주수
|
||||
public let listedStockCount: String
|
||||
|
||||
/// 평균 거래량
|
||||
public let averageVolume: String
|
||||
|
||||
/// N일전종가대비현재가대비율
|
||||
public let nDayBeforeClosingPriceDiffRatio: String
|
||||
|
||||
/// 거래량증가율
|
||||
public let volumeIncreaseRate: String
|
||||
|
||||
/// 거래량 회전율
|
||||
public let volumeTurnoverRate: String
|
||||
|
||||
/// N일 거래량 회전율
|
||||
public let nDayVolumeTurnoverRate: String
|
||||
|
||||
/// 평균 거래 대금
|
||||
public let averageTradingAmount: String
|
||||
|
||||
/// 거래대금회전율
|
||||
public let tradingAmountTurnoverRate: String
|
||||
|
||||
/// N일 거래대금 회전율
|
||||
public let nDayTradingAmountTurnoverRate: String
|
||||
|
||||
/// 누적 거래 대금
|
||||
public let accumulatedTradingAmount: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case htsProductName = "hts_kor_isnm"
|
||||
case shortProductNo = "mksc_shrn_iscd"
|
||||
case dataRank = "data_rank"
|
||||
case currentStockPrice = "stck_prpr"
|
||||
|
||||
case previousDayVariableRatioSign = "prdy_vrss_sign"
|
||||
case previousDayVariableRatio = "prdy_vrss"
|
||||
case previousDayDiffRatio = "prdy_ctrt"
|
||||
case accumulatedVolume = "acml_vol"
|
||||
case previousDayVolume = "prdy_vol"
|
||||
case listedStockCount = "lstn_stcn"
|
||||
case averageVolume = "avrg_vol"
|
||||
|
||||
case nDayBeforeClosingPriceDiffRatio = "n_befr_clpr_vrss_prpr_rate"
|
||||
case volumeIncreaseRate = "vol_inrt"
|
||||
case volumeTurnoverRate = "vol_tnrt"
|
||||
case nDayVolumeTurnoverRate = "nday_vol_tnrt"
|
||||
case averageTradingAmount = "avrg_tr_pbmn"
|
||||
case tradingAmountTurnoverRate = "tr_pbmn_tnrt"
|
||||
case nDayTradingAmountTurnoverRate = "nday_tr_pbmn_tnrt"
|
||||
case accumulatedTradingAmount = "acml_tr_pbmn"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
KissMe/Foreign/ForeignFutures.swift
Normal file
10
KissMe/Foreign/ForeignFutures.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// ForeignFutures.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TODO: WORK
|
||||
10
KissMe/Foreign/ForeignStock.swift
Normal file
10
KissMe/Foreign/ForeignStock.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// ForeignStock.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TODO: WORK
|
||||
10
KissMe/Foreign/ForeignStockPrice.swift
Normal file
10
KissMe/Foreign/ForeignStockPrice.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// ForeignStockPrice.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TODO: WORK
|
||||
28
KissMe/KissAccount.swift
Normal file
28
KissMe/KissAccount.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// KissAccount.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public class KissAccount {
|
||||
|
||||
let credential: Credential
|
||||
|
||||
var accessTokenLock = NSLock()
|
||||
var accessToken: String?
|
||||
|
||||
public init(credential: Credential) {
|
||||
self.credential = credential
|
||||
self.accessToken = nil
|
||||
}
|
||||
|
||||
func setAccessToken(_ accessToken: String?) {
|
||||
accessTokenLock.lock()
|
||||
self.accessToken = accessToken
|
||||
accessTokenLock.unlock()
|
||||
}
|
||||
}
|
||||
13
KissMe/KissMe.docc/KissMe.md
Executable file
13
KissMe/KissMe.docc/KissMe.md
Executable file
@@ -0,0 +1,13 @@
|
||||
# ``KissMe``
|
||||
|
||||
<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->
|
||||
|
||||
## Overview
|
||||
|
||||
<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->
|
||||
|
||||
## Topics
|
||||
|
||||
### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->
|
||||
|
||||
- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
|
||||
18
KissMe/KissMe.h
Normal file
18
KissMe/KissMe.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// KissMe.h
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/09.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for KissMe.
|
||||
FOUNDATION_EXPORT double KissMeVersionNumber;
|
||||
|
||||
//! Project version string for KissMe.
|
||||
FOUNDATION_EXPORT const unsigned char KissMeVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <KissMe/PublicHeader.h>
|
||||
|
||||
|
||||
175
KissMe/Login/Login.swift
Normal file
175
KissMe/Login/Login.swift
Normal file
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// Login.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
///. OAuth인증 - 접근토큰발급(P)[인증-001]
|
||||
///
|
||||
public struct LoginAuthRequest: AuthRequest {
|
||||
public typealias KResult = TokenResult
|
||||
|
||||
public var url: String { "/oauth2/tokenP" }
|
||||
public var method: Method { .post }
|
||||
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"grant_type": "client_credentials",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public var credential: Credential
|
||||
|
||||
public init(credential: Credential) {
|
||||
self.credential = credential
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// OAuth인증 - 접근토큰폐기(P)[인증-002]
|
||||
///
|
||||
public struct LogoutAuthRequest: AuthRequest {
|
||||
public typealias KResult = MessageResult
|
||||
|
||||
public var url: String { "/oauth2/revokeP" }
|
||||
public var method: Method { .post }
|
||||
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret,
|
||||
"token": accessToken
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public var credential: Credential
|
||||
|
||||
let accessToken: String
|
||||
|
||||
public init(credential: Credential, accessToken: String) {
|
||||
self.credential = credential
|
||||
self.accessToken = accessToken
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// OAuth인증 - Hashkey
|
||||
///
|
||||
public struct HashKeyAuthRequest: AuthRequest {
|
||||
public typealias KResult = HashKeyResult
|
||||
|
||||
public var url: String { "/uapi/hashkey" }
|
||||
public var method: Method { .post }
|
||||
|
||||
public var header: [String: String?] {
|
||||
[
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret
|
||||
]
|
||||
}
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"JsonBody": jsonBody
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
let jsonBody: String
|
||||
|
||||
public init(credential: Credential, jsonBody: String) {
|
||||
self.credential = credential
|
||||
self.jsonBody = jsonBody
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// OAuth인증 - 실시간 (웹소켓) 접속키 발급[실시간-000]
|
||||
///
|
||||
public struct ApprovalKeyAuthRequest: AuthRequest {
|
||||
public typealias KResult = ApprovalKeyResult
|
||||
|
||||
public var url: String { "/oauth2/Approval" }
|
||||
public var method: Method { .post }
|
||||
|
||||
public var body: [String: Any] {
|
||||
[
|
||||
"grant_type": "client_credentials",
|
||||
"appkey": credential.appKey,
|
||||
"appsecret": credential.appSecret
|
||||
]
|
||||
}
|
||||
public var result: KResult? = nil
|
||||
public let credential: Credential
|
||||
|
||||
public init(credential: Credential) {
|
||||
self.credential = credential
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension KissAccount {
|
||||
|
||||
public func login() async throws -> Bool {
|
||||
return try await withUnsafeThrowingContinuation { continuation in
|
||||
|
||||
let request = LoginAuthRequest(credential: credential)
|
||||
request.query { result in
|
||||
switch result {
|
||||
case .success(let result):
|
||||
self.setAccessToken(result.accessToken)
|
||||
continuation.resume(returning: true)
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func logout() async throws -> Bool {
|
||||
return try await withUnsafeThrowingContinuation { continuation in
|
||||
guard let accessToken = accessToken else {
|
||||
continuation.resume(throwing: GeneralError.invalidAccessToken)
|
||||
return
|
||||
}
|
||||
|
||||
let request = LogoutAuthRequest(credential: credential, accessToken: accessToken)
|
||||
request.query { result in
|
||||
switch result {
|
||||
case .success(let result):
|
||||
if result.code == 200 {
|
||||
self.setAccessToken(nil)
|
||||
continuation.resume(returning: true)
|
||||
}
|
||||
else {
|
||||
let error = NSError(domain: "KissLogout", code: result.code, userInfo: [
|
||||
NSLocalizedDescriptionKey: result.message
|
||||
])
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func hashKey(json: String, completion: @escaping (Result<HashKeyResult, Error>) -> Void) {
|
||||
let request = HashKeyAuthRequest(credential: credential, jsonBody: json)
|
||||
request.query(completion: completion)
|
||||
}
|
||||
|
||||
|
||||
public func approvalKey(completion: @escaping (Result<ApprovalKeyResult, Error>) -> Void) {
|
||||
let request = ApprovalKeyAuthRequest(credential: credential)
|
||||
request.query(completion: completion)
|
||||
}
|
||||
}
|
||||
42
KissMe/Login/LoginResult.swift
Normal file
42
KissMe/Login/LoginResult.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// LoginResult.swift
|
||||
// KissMe
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/14.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public struct TokenResult: Codable {
|
||||
public let accessToken: String
|
||||
public let tokenType: String
|
||||
public let expiresIn: Int
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case accessToken = "access_token"
|
||||
case tokenType = "token_type"
|
||||
case expiresIn = "expires_in"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct MessageResult: Codable {
|
||||
public let code: Int
|
||||
public let message: String
|
||||
}
|
||||
|
||||
|
||||
public struct HashKeyResult: Codable {
|
||||
public let body: String
|
||||
public let hash: String
|
||||
}
|
||||
|
||||
|
||||
public struct ApprovalKeyResult: Codable {
|
||||
public let approvalKey: String
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case approvalKey = "approval_key"
|
||||
}
|
||||
}
|
||||
305
KissMeConsole/KissMeConsole.xcodeproj/project.pbxproj
Normal file
305
KissMeConsole/KissMeConsole.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,305 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
341F5ED42A0A8B9000962D48 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5ED32A0A8B9000962D48 /* main.swift */; };
|
||||
341F5EDC2A0A8C4600962D48 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EDB2A0A8C4600962D48 /* KissMe.framework */; };
|
||||
341F5F052A13B82F00962D48 /* test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5F042A13B82F00962D48 /* test.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
341F5ECE2A0A8B9000962D48 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
341F5ED02A0A8B9000962D48 /* KissMeConsole */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KissMeConsole; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
341F5ED32A0A8B9000962D48 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
341F5EDB2A0A8C4600962D48 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
341F5F042A13B82F00962D48 /* test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = test.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
341F5ECD2A0A8B9000962D48 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5EDC2A0A8C4600962D48 /* KissMe.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
341F5EC72A0A8B9000962D48 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5ED22A0A8B9000962D48 /* KissMeConsole */,
|
||||
341F5ED12A0A8B9000962D48 /* Products */,
|
||||
341F5EDA2A0A8C4600962D48 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5ED12A0A8B9000962D48 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5ED02A0A8B9000962D48 /* KissMeConsole */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5ED22A0A8B9000962D48 /* KissMeConsole */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5ED32A0A8B9000962D48 /* main.swift */,
|
||||
341F5F042A13B82F00962D48 /* test.swift */,
|
||||
);
|
||||
path = KissMeConsole;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
341F5EDA2A0A8C4600962D48 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
341F5EDB2A0A8C4600962D48 /* KissMe.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
341F5ECF2A0A8B9000962D48 /* KissMeConsole */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 341F5ED72A0A8B9000962D48 /* Build configuration list for PBXNativeTarget "KissMeConsole" */;
|
||||
buildPhases = (
|
||||
341F5ECC2A0A8B9000962D48 /* Sources */,
|
||||
341F5ECD2A0A8B9000962D48 /* Frameworks */,
|
||||
341F5ECE2A0A8B9000962D48 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = KissMeConsole;
|
||||
productName = KissMeConsole;
|
||||
productReference = 341F5ED02A0A8B9000962D48 /* KissMeConsole */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
341F5EC82A0A8B9000962D48 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1430;
|
||||
TargetAttributes = {
|
||||
341F5ECF2A0A8B9000962D48 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 341F5ECB2A0A8B9000962D48 /* Build configuration list for PBXProject "KissMeConsole" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 341F5EC72A0A8B9000962D48;
|
||||
productRefGroup = 341F5ED12A0A8B9000962D48 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
341F5ECF2A0A8B9000962D48 /* KissMeConsole */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
341F5ECC2A0A8B9000962D48 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
341F5ED42A0A8B9000962D48 /* main.swift in Sources */,
|
||||
341F5F052A13B82F00962D48 /* test.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
341F5ED52A0A8B9000962D48 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
341F5ED62A0A8B9000962D48 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
341F5ED82A0A8B9000962D48 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
341F5ED92A0A8B9000962D48 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = NYU8YAYHF8;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
341F5ECB2A0A8B9000962D48 /* Build configuration list for PBXProject "KissMeConsole" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
341F5ED52A0A8B9000962D48 /* Debug */,
|
||||
341F5ED62A0A8B9000962D48 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
341F5ED72A0A8B9000962D48 /* Build configuration list for PBXNativeTarget "KissMeConsole" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
341F5ED82A0A8B9000962D48 /* Debug */,
|
||||
341F5ED92A0A8B9000962D48 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 341F5EC82A0A8B9000962D48 /* Project object */;
|
||||
}
|
||||
7
KissMeConsole/KissMeConsole.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
KissMeConsole/KissMeConsole.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "341F5ECF2A0A8B9000962D48"
|
||||
BuildableName = "KissMeConsole"
|
||||
BlueprintName = "KissMeConsole"
|
||||
ReferencedContainer = "container:KissMeConsole.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "YES"
|
||||
customWorkingDirectory = "$(SRCROOT)/../bin"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
viewDebuggingEnabled = "No">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "341F5ECF2A0A8B9000962D48"
|
||||
BuildableName = "KissMeConsole"
|
||||
BlueprintName = "KissMeConsole"
|
||||
ReferencedContainer = "container:KissMeConsole.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "341F5ECF2A0A8B9000962D48"
|
||||
BuildableName = "KissMeConsole"
|
||||
BlueprintName = "KissMeConsole"
|
||||
ReferencedContainer = "container:KissMeConsole.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
128
KissMeConsole/KissMeConsole/main.swift
Normal file
128
KissMeConsole/KissMeConsole/main.swift
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// main.swift
|
||||
// KissMeConsole
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/09.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import KissMe
|
||||
|
||||
|
||||
class KissConsole {
|
||||
var credential: Credential? = nil
|
||||
var account: KissAccount? = nil
|
||||
|
||||
enum KissCommand: String {
|
||||
case quit = "quit"
|
||||
case loginMock = "login mock"
|
||||
case loginReal = "login real"
|
||||
case logout = "logout"
|
||||
case search = "search"
|
||||
}
|
||||
|
||||
var isLogined: Bool {
|
||||
account != nil
|
||||
}
|
||||
|
||||
|
||||
func onLoginMock() async {
|
||||
guard !isLogined else {
|
||||
print("Already loginged")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
credential = try KissCredential(isMock: true)
|
||||
account = KissAccount(credential: credential!)
|
||||
if try await account!.login() {
|
||||
print("Success")
|
||||
}
|
||||
} catch {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func onLoginReal() async {
|
||||
guard !isLogined else {
|
||||
print("Already loginged")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
credential = try KissCredential(isMock: false)
|
||||
account = KissAccount(credential: credential!)
|
||||
if try await account!.login() {
|
||||
print("Success")
|
||||
}
|
||||
} catch {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func onLogout() async {
|
||||
guard isLogined else {
|
||||
print("Already logout")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try await account?.logout()
|
||||
credential = nil
|
||||
account = nil
|
||||
} catch {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func onSearch(_ arg: [String]) async {
|
||||
guard isLogined else {
|
||||
print("Already logout")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try await account?.getVolumeRanking(divisionClass: .all, belongClass: .averageVolume)
|
||||
} catch {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func run() {
|
||||
print("Enter command:")
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var loop = true
|
||||
|
||||
while loop {
|
||||
guard let line = readLine(strippingNewline: true) else {
|
||||
continue
|
||||
}
|
||||
let args = line.split(separator: " ")
|
||||
let single = args.prefix(upTo: min(2, args.count)).joined(separator: " ")
|
||||
let cmd = KissCommand(rawValue: single)
|
||||
|
||||
Task {
|
||||
switch cmd {
|
||||
case .quit: break
|
||||
case .loginMock: await onLoginMock()
|
||||
case .loginReal: await onLoginReal()
|
||||
case .logout: await onLogout()
|
||||
case .search: await onSearch(args.suffix(from: 1).map { String($0) })
|
||||
default:
|
||||
print("Unknown command: \(single)")
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
|
||||
loop = (cmd != .quit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
KissConsole().run()
|
||||
61
KissMeConsole/KissMeConsole/test.swift
Normal file
61
KissMeConsole/KissMeConsole/test.swift
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// test.swift
|
||||
// KissMeConsole
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/16.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import KissMe
|
||||
|
||||
|
||||
func test_login_get_volume_ranking() async {
|
||||
let isMock = false
|
||||
let credential: Credential
|
||||
|
||||
do {
|
||||
/// isMock 이 true 이면, mock-server.json 에서 로딩하여 생성
|
||||
/// isMock 이 false 이면, real-server.json 에서 로딩하여 생성
|
||||
/// server.json 의 구조
|
||||
/// {
|
||||
/// "isMock": true,
|
||||
/// "accountNo": "12345678-90"
|
||||
/// "appKey": "xxxxxxxx",
|
||||
/// "appSecret": "yyyyyyyyyyyyyyyyyy"
|
||||
/// }
|
||||
///
|
||||
credential = try KissCredential(isMock: isMock)
|
||||
} catch {
|
||||
print("\(error)")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let account = KissAccount(credential: credential)
|
||||
do {
|
||||
if try await account.login() {
|
||||
let result = try await account.getVolumeRanking(divisionClass: .equity, belongClass: .averageVolume)
|
||||
print("\(result)")
|
||||
}
|
||||
} catch {
|
||||
print("\(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func test_json_result() {
|
||||
let str = "{\"rt_cd\":\"1\",\"msg_cd\":\"EGW00205\",\"msg1\":\"credentials_type이 유효하지 않습니다.(Bearer)\"}"
|
||||
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
decoder.keyDecodingStrategy = .useDefaultKeys
|
||||
|
||||
let data = Data(str.utf8)
|
||||
let result = try decoder.decode(VolumeRankResult.self, from: data)
|
||||
print("\(result)")
|
||||
}
|
||||
catch {
|
||||
print("\(error)")
|
||||
}
|
||||
}
|
||||
36
KissMeTests/KissMeTests.swift
Normal file
36
KissMeTests/KissMeTests.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// KissMeTests.swift
|
||||
// KissMeTests
|
||||
//
|
||||
// Created by ened-book-m1 on 2023/05/09.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import KissMe
|
||||
|
||||
class KissMeTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
## About KissMe
|
||||
|
||||
KissMe 는 KIS API 를 연동한 swift 라이브러리입니다.
|
||||
|
||||
KissMeConsole 은 command line 에서 인터렉티브 명령어로 API 호출을 테스트해볼 수 있는 도구입니다.
|
||||
|
||||
KissCredential 에서 사용하는 json 의 양식은 다음과 같습니다.
|
||||
|
||||
```json
|
||||
{
|
||||
"isMock": false,
|
||||
"accountNo": "12345678-90",
|
||||
"appKey": "xxxxxxxxxxx",
|
||||
"appSecret": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
|
||||
}
|
||||
```
|
||||
|
||||
* `isMock` 값이 `true` 이면 모의서버, `false` 이면 실전서버를 의미합니다.
|
||||
* `accountNo` 에는 계좌번호를 의미합니다. 8-2 형태의 숫자로 입력합니다.
|
||||
* `appKey` 는 한국투자증권 홈페이지에서 발급받은 appkey 입니다.
|
||||
* `appSecret` 는 한국투자증권 홈페이지에서 발급받은 appsecret 입니다.
|
||||
Reference in New Issue
Block a user