Add KMI-0005 initial code

This commit is contained in:
2023-06-20 18:30:04 +09:00
parent 929d59149c
commit bbf7d03827
37 changed files with 1271 additions and 292 deletions

View File

@@ -40,6 +40,14 @@ extension Date {
public static var appTime: TimeInterval {
ProcessInfo.processInfo.systemUptime
}
public static func date(yyyyMMdd: String, HHmmss: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "KST")
dateFormatter.dateFormat = "yyyyMMddHHmmss"
let fullDate = yyyyMMdd + HHmmss
return dateFormatter.date(from: fullDate)
}
}
@@ -105,6 +113,25 @@ extension URL {
#endif
extension URL {
public var isDirectoryExists: Bool? {
var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: path, isDirectory: &isDir) {
return isDir.boolValue
}
return false
}
public var isFileExists: Bool? {
var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: path, isDirectory: &isDir) {
return isDir.boolValue == false
}
return false
}
}
@_silgen_name("swift_EnumCaseName")
func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
@@ -114,3 +141,201 @@ public func getEnumCaseName<T>(for value: T) -> String? {
}
return nil
}
extension FileManager {
public static func subPathFiles(_ subpath: String) -> FileManager.DirectoryEnumerator? {
let baseUrl = URL.currentDirectory().appending(path: subpath)
let manager = FileManager.default
let resourceKeys : [URLResourceKey] = []
let enumerator = manager.enumerator(at: baseUrl, includingPropertiesForKeys: resourceKeys, options: [.skipsHiddenFiles]) { (url, error) -> Bool in
print("directoryEnumerator error at \(url): ", error)
return true
}
return enumerator
}
}
public func valueToString(_ any: Any) -> String {
switch any {
case let s as String: return s
case let i as Int8: return String(i)
case let i as UInt8: return String(i)
case let i as Int16: return String(i)
case let i as UInt16: return String(i)
case let i as Int32: return String(i)
case let i as UInt32: return String(i)
case let i as Int: return String(i)
case let i as UInt: return String(i)
case let i as Int64: return String(i)
case let i as UInt64: return String(i)
case let f as Float16: return String(f)
case let f as Float32: return String(f)
case let f as Float: return String(f)
case let f as Float64: return String(f)
case let d as Double: return String(d)
case let raw as any RawRepresentable:
switch raw.rawValue {
case let s as String: return s
case let i as Int8: return String(i)
case let i as UInt8: return String(i)
case let i as Int16: return String(i)
case let i as UInt16: return String(i)
case let i as Int32: return String(i)
case let i as UInt32: return String(i)
case let i as Int: return String(i)
case let i as UInt: return String(i)
case let i as Int64: return String(i)
case let i as UInt64: return String(i)
default:
return ""
}
case let c as CustomStringConvertible: return c.description
default:
return ""
}
}
extension Array where Element: PropertyIterable {
public func writeCsv(toFile file: URL, appendable: Bool = false, localized: Bool) throws {
if appendable, file.isFileExists == true {
try appendAtEnd(ofCsv: file)
}
else {
try overwrite(toCsv: file, localized: localized)
}
return
// Nested function
func appendAtEnd(ofCsv file: URL) throws {
let oldHeader = try String.readCsvHeader(fromFile: file)
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map{ $0.0 }
if oldHeader != header {
let (_, field) = oldHeader.getDiff(from: header) ?? (-1, "")
throw GeneralError.incorrectCsvHeaderField(field)
}
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.writeAppending(toFile: file.path)
}
// Nested function
func overwrite(toCsv file: URL, localized: Bool) throws {
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map { prop in
localized ? localizeString(prop.0): prop.0
}.joined(separator: ",").appending("\n")
stringCsv.append(header)
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.write(toFile: file.path, atomically: true, encoding: .utf8)
}
}
public static func readCsv(fromFile: URL, verifyHeader: Bool = true) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(contentsOfFile: fromFile.path, encoding: .utf8)
let items = stringCsv.split(separator: "\n")
guard items.count > 0 else {
return []
}
var headerItems = [String]()
var elements = [Element]()
for (index, item) in items.enumerated() {
if index == 0 {
headerItems = item.split(separator: ",").map { String($0) }
continue
}
let array = item.split(separator: ",").map { String($0) }
let element = try Element(array: array)
if index == 1, verifyHeader {
// Validate property with header
let properties = try element.allProperties()
for (label, _) in properties {
if false == headerItems.contains(where: { $0 == label }) {
throw GeneralError.headerNoFiendName(label)
}
}
}
elements.append(element)
}
return elements
}
}
extension Array where Element == String {
func getDiff(from: [Element]) -> (Int, String)? {
for (index, s) in enumerated() {
guard index < from.count else {
return (index, s)
}
if s != from[index] {
return (index, s)
}
}
return nil
}
}
extension String {
public init(firstLineOfFile path: String) throws {
guard let filePointer = fopen(path, "r") else {
throw GeneralError.cannotReadFile
}
var cLineBytes: UnsafeMutablePointer<CChar>? = nil
defer {
fclose(filePointer)
cLineBytes?.deallocate()
}
var lineCap: Int = 0
let bytesRead = getline(&cLineBytes, &lineCap, filePointer)
guard bytesRead > 0, let cLineBytes = cLineBytes else {
throw GeneralError.cannotReadFileLine
}
guard let str = String(cString: cLineBytes, encoding: .utf8) else {
throw GeneralError.cannotReadFileToConvertString
}
self = str.trimmingCharacters(in: .whitespacesAndNewlines)
}
public static func readCsvHeader(fromFile: URL) throws -> [String] {
let header = try String(firstLineOfFile: fromFile.path)
return header.split(separator: ",").map { String($0) }
}
public func writeAppending(toFile path: String) throws {
guard let handle = FileHandle(forWritingAtPath: path) else {
throw GeneralError.cannotReadFile
}
defer {
try? handle.close()
}
_ = handle.seekToEndOfFile()
handle.write(Data(utf8))
}
}

View File

@@ -0,0 +1,50 @@
//
// LocalContext.swift
// KissMeConsole
//
// Created by ened-book-m1 on 2023/06/10.
//
import Foundation
public struct LocalName: Codable, PropertyIterable, ArrayDecodable {
public let fieldName: String
public let localizedName: String
public init(array: [String]) throws {
guard array.count == 2 else {
throw GeneralError.incorrectArrayItems
}
fieldName = array[0]
localizedName = array[1]
}
}
public struct LocalContext {
public static var shared = LocalContext()
public var localNamesDic: [String: LocalName] = .init()
mutating public func load(_ localNamesUrl: URL) {
do {
let names = try [LocalName].readCsv(fromFile: localNamesUrl)
var nameDic = [String: LocalName]()
for name in names {
nameDic[name.fieldName] = name
if name.localizedName.isEmpty {
assertionFailure("Cannot load \(localNamesUrl.path) - no localized name for \(name.fieldName)")
}
}
localNamesDic = nameDic
} catch {
print(error)
assertionFailure("Cannot load \(localNamesUrl.path)")
localNamesDic = [:]
}
}
}
public func localizeString(_ str: String) -> String {
return LocalContext.shared.localNamesDic[str]?.localizedName ?? str
}

View File

@@ -58,6 +58,16 @@ public enum BelongClassCode: String, CustomStringConvertible {
case .averageTransactionValueTurnoverRate: return "4:평균거래금액회전율"
}
}
public var fileBelong: String {
switch self {
case .averageVolume: return "av"
case .volumeIncreaseRate: return "vir"
case .averageVolumeTurnoverRate: return "avtr"
case .transactionValue: return "tv"
case .averageTransactionValueTurnoverRate: return "atvtr"
}
}
}

View File

@@ -0,0 +1,33 @@
//
// IndexResult.swift
// KissMe
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
public struct KissIndexResult: Codable {
public let code: Int
public let message: String
public let kmi: String
public let output: [Output]
public struct Output: Codable {
public let shortCode: String
public let weight: Double
public init(shortCode: String, weight: Double) {
self.shortCode = shortCode
self.weight = weight
}
}
public init(code: Int, message: String, kmi: String, output: [Output]) {
self.code = code
self.message = message
self.kmi = kmi
self.output = output
}
}

View File

@@ -120,220 +120,7 @@ extension Date {
}
func valueToString(_ any: Any) -> String {
switch any {
case let s as String: return s
case let i as Int8: return String(i)
case let i as UInt8: return String(i)
case let i as Int16: return String(i)
case let i as UInt16: return String(i)
case let i as Int32: return String(i)
case let i as UInt32: return String(i)
case let i as Int: return String(i)
case let i as UInt: return String(i)
case let i as Int64: return String(i)
case let i as UInt64: return String(i)
case let f as Float16: return String(f)
case let f as Float32: return String(f)
case let f as Float: return String(f)
case let f as Float64: return String(f)
case let d as Double: return String(d)
case let raw as any RawRepresentable:
switch raw.rawValue {
case let s as String: return s
case let i as Int8: return String(i)
case let i as UInt8: return String(i)
case let i as Int16: return String(i)
case let i as UInt16: return String(i)
case let i as Int32: return String(i)
case let i as UInt32: return String(i)
case let i as Int: return String(i)
case let i as UInt: return String(i)
case let i as Int64: return String(i)
case let i as UInt64: return String(i)
default:
return ""
}
case let c as CustomStringConvertible: return c.description
default:
return ""
}
}
extension Array where Element: PropertyIterable {
func writeCsv(toFile file: URL, appendable: Bool = false, localized: Bool) throws {
if appendable, file.isFileExists == true {
try appendAtEnd(ofCsv: file)
}
else {
try overwrite(toCsv: file, localized: localized)
}
return
// Nested function
func appendAtEnd(ofCsv file: URL) throws {
let oldHeader = try String.readCsvHeader(fromFile: file)
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map{ $0.0 }
if oldHeader != header {
let (_, field) = oldHeader.getDiff(from: header) ?? (-1, "")
throw GeneralError.incorrectCsvHeaderField(field)
}
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.writeAppending(toFile: file.path)
}
// Nested function
func overwrite(toCsv file: URL, localized: Bool) throws {
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map { prop in
localized ? localizeString(prop.0): prop.0
}.joined(separator: ",").appending("\n")
stringCsv.append(header)
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.write(toFile: file.path, atomically: true, encoding: .utf8)
}
}
static func readCsv(fromFile: URL, verifyHeader: Bool = true) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(contentsOfFile: fromFile.path, encoding: .utf8)
let items = stringCsv.split(separator: "\n")
guard items.count > 0 else {
return []
}
var headerItems = [String]()
var elements = [Element]()
for (index, item) in items.enumerated() {
if index == 0 {
headerItems = item.split(separator: ",").map { String($0) }
continue
}
let array = item.split(separator: ",").map { String($0) }
let element = try Element(array: array)
if index == 1, verifyHeader {
// Validate property with header
let properties = try element.allProperties()
for (label, _) in properties {
if false == headerItems.contains(where: { $0 == label }) {
throw GeneralError.headerNoFiendName(label)
}
}
}
elements.append(element)
}
return elements
}
}
extension Array where Element == String {
func getDiff(from: [Element]) -> (Int, String)? {
for (index, s) in enumerated() {
guard index < from.count else {
return (index, s)
}
if s != from[index] {
return (index, s)
}
}
return nil
}
}
extension String {
init(firstLineOfFile path: String) throws {
guard let filePointer = fopen(path, "r") else {
throw GeneralError.cannotReadFile
}
var cLineBytes: UnsafeMutablePointer<CChar>? = nil
defer {
fclose(filePointer)
cLineBytes?.deallocate()
}
var lineCap: Int = 0
let bytesRead = getline(&cLineBytes, &lineCap, filePointer)
guard bytesRead > 0, let cLineBytes = cLineBytes else {
throw GeneralError.cannotReadFileLine
}
guard let str = String(cString: cLineBytes, encoding: .utf8) else {
throw GeneralError.cannotReadFileToConvertString
}
self = str.trimmingCharacters(in: .whitespacesAndNewlines)
}
static func readCsvHeader(fromFile: URL) throws -> [String] {
let header = try String(firstLineOfFile: fromFile.path)
return header.split(separator: ",").map { String($0) }
}
func writeAppending(toFile path: String) throws {
guard let handle = FileHandle(forWritingAtPath: path) else {
throw GeneralError.cannotReadFile
}
defer {
try? handle.close()
}
_ = handle.seekToEndOfFile()
handle.write(Data(utf8))
}
}
extension URL {
var isDirectoryExists: Bool? {
var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: path, isDirectory: &isDir) {
return isDir.boolValue
}
return false
}
var isFileExists: Bool? {
var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: path, isDirectory: &isDir) {
return isDir.boolValue == false
}
return false
}
}
extension FileManager {
static func subPathFiles(_ subpath: String) -> FileManager.DirectoryEnumerator? {
let baseUrl = URL.currentDirectory().appending(path: subpath)
let manager = FileManager.default
let resourceKeys : [URLResourceKey] = []
let enumerator = manager.enumerator(at: baseUrl, includingPropertiesForKeys: resourceKeys, options: [.skipsHiddenFiles]) { (url, error) -> Bool in
print("directoryEnumerator error at \(url): ", error)
return true
}
return enumerator
}
/// period: If nil, all period of csv collected.
/// candleDate: If nil, all date of csv collected.

View File

@@ -225,15 +225,3 @@ extension KissConsole {
return .ok
}
}
extension BelongClassCode {
var fileBelong: String {
switch self {
case .averageVolume: return "av"
case .volumeIncreaseRate: return "vir"
case .averageVolumeTurnoverRate: return "avtr"
case .transactionValue: return "tv"
case .averageTransactionValueTurnoverRate: return "atvtr"
}
}
}

View File

@@ -185,7 +185,21 @@ extension KissConsole {
let result = try await account!.getHolyday(baseDate: day)
do {
try result.output?.writeCsv(toFile: KissConsole.holidayUrl, localized: localized)
var olds = try [HolidyResult.OutputDetail].readCsv(fromFile: KissConsole.holidayUrl)
if let output = result.output {
/// Merge current holidays and new holidays
var recents = output.map { $0 }
for old in olds {
if let _ = recents.first(where: { $0.baseDate == old.baseDate }) {
continue
}
recents.append(old)
}
recents.sort(by: { $0.baseDate < $1.baseDate })
/// Write back with merged one
try recents.writeCsv(toFile: KissConsole.holidayUrl, localized: localized)
}
} catch {
print(error)
}

View File

@@ -328,7 +328,7 @@ extension KissConsole {
}
private func loadLocalName() {
_ = LocalContext.shared.localNamesDic
LocalContext.shared.load(KissConsole.localNamesUrl)
}
func setCurrent(productNo: String) {
@@ -1118,3 +1118,9 @@ private extension Array {
return suffix(from: from).map { String($0) }
}
}
enum OnOff: String {
case on
case off
}

View File

@@ -1,55 +0,0 @@
//
// LocalContext.swift
// KissMeConsole
//
// Created by ened-book-m1 on 2023/06/10.
//
import Foundation
import KissMe
struct LocalName: Codable, PropertyIterable, ArrayDecodable {
let fieldName: String
let localizedName: String
init(array: [String]) throws {
guard array.count == 2 else {
throw GeneralError.incorrectArrayItems
}
fieldName = array[0]
localizedName = array[1]
}
}
struct LocalContext {
static var shared = LocalContext()
lazy var localNamesDic: [String: LocalName] = {
do {
let names = try [LocalName].readCsv(fromFile: KissConsole.localNamesUrl)
var nameDic = [String: LocalName]()
for name in names {
nameDic[name.fieldName] = name
if name.localizedName.isEmpty {
assertionFailure("Cannot load \(KissConsole.localNamesUrl.path) - no localized name for \(name.fieldName)")
}
}
return nameDic
} catch {
print(error)
assertionFailure("Cannot load \(KissConsole.localNamesUrl.path)")
return [:]
}
}()
}
func localizeString(_ str: String) -> String {
return LocalContext.shared.localNamesDic[str]?.localizedName ?? str
}
enum OnOff: String {
case on
case off
}

34
KissMeIndex/Package.swift Normal file
View File

@@ -0,0 +1,34 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "KissMeIndex",
platforms: [
.macOS(.v13), .iOS(.v14), .tvOS(.v14)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.executable(
name: "KissMeIndex",
targets: ["KissMeIndex"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
//.package(url: "../KissMe", from: "1.0.0"),
.package(path: "../KissMe"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "KissMeIndex",
dependencies: ["KissMe"],
path: "Sources"),
.testTarget(
name: "KissMeIndexTests",
dependencies: ["KissMeIndex"],
path: "Tests"),
]
)

View File

@@ -0,0 +1,16 @@
//
// KissIndex+0001.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
extension KissIndex {
func indexSet_0001(date: Date, config: String?, kmi: KissIndexType) {
// TODO: work
}
}

View File

@@ -0,0 +1,16 @@
//
// KissIndex+0002.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
extension KissIndex {
func indexSet_0002(date: Date, config: String?, kmi: KissIndexType) {
// TODO: work
}
}

View File

@@ -0,0 +1,16 @@
//
// KissIndex+0003.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
extension KissIndex {
func indexSet_0003(date: Date, config: String?, kmi: KissIndexType) {
// TODO: work
}
}

View File

@@ -0,0 +1,16 @@
//
// KissIndex+0004.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
extension KissIndex {
func indexSet_0004(date: Date, config: String?, kmi: KissIndexType) {
// TODO: work
}
}

View File

@@ -0,0 +1,112 @@
//
// KissIndex+0005.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
import KissMe
extension KissIndex {
func indexSet_0005(date: Date, config: String?, kmi: KissIndexType) {
//let belongs: [BelongClassCode] = [.averageVolume, .volumeIncreaseRate, .averageVolumeTurnoverRate, .transactionValue, .averageTransactionValueTurnoverRate]
let belongs: [BelongClassCode] = [.averageVolume]
do {
var scoreMap = [String: Int]()
for belong in belongs {
let topUrl = try KissIndex.pickNearTopProductsUrl(belong, date: date)
let data = try [VolumeRankResult.OutputDetail].readCsv(fromFile: topUrl, verifyHeader: true)
for (index, item) in data.enumerated() {
let score = (30 - index)
if let _ = scoreMap[item.shortProductNo] {
scoreMap[item.shortProductNo]! += score
}
else {
scoreMap[item.shortProductNo] = score
}
}
}
let totalScores = scoreMap.reduce(0, { $0 + $1.value })
let scoreArray = scoreMap.map { ($0.key, $0.value) }.sorted(by: { $0.1 > $1.1 })
var outputs = [KissIndexResult.Output]()
for array in scoreArray {
let weight = Double(array.1) / Double(totalScores)
let output = KissIndexResult.Output(shortCode: array.0, weight: weight)
outputs.append(output)
}
writeOutput(outputs, kmi: kmi)
}
catch {
writeError(error, kmi: kmi)
}
}
static func pickNearTopProductsUrl(_ belong: BelongClassCode, date: Date) throws -> URL {
let subPath = "data/top30/\(date.yyyyMMdd)"
let dayFile = "top30-\(belong.fileBelong)-\(date.yyyyMMdd)-"
guard let enumerator = FileManager.subPathFiles(subPath) else {
throw GeneralError.noCsvFile
}
let dateHHmmss = date.HHmmss
var csvUrls = [URL]()
for case let fileUrl as URL in enumerator {
guard fileUrl.pathExtension == "csv" else {
continue
}
let dayPrefixFile = fileUrl.lastPathComponent.prefix(dayFile.utf8.count)
let hourOfFile = fileUrl.lastPathComponent.suffix(10).split(separator: ".")
if dayPrefixFile == dayFile, hourOfFile.count == 2 {
let hourFrag = String(hourOfFile[0])
if hourFrag <= dateHHmmss {
csvUrls.append(fileUrl)
}
}
}
/// Sorted by near date
csvUrls.sort(by: { dateHHmmss.diffSecondsTwoCsvHHmmss($0.lastPathComponent) < dateHHmmss.diffSecondsTwoCsvHHmmss($1.lastPathComponent) })
//csvUrls.forEach( { print($0) })
guard let nearestFile = csvUrls.first else {
throw GeneralError.noCsvFile
}
//print("nearest file: \(nearestFile) at \(date.yyyyMMdd_HHmmss_forTime)")
return nearestFile
}
}
extension String {
var csvHHmmssBySeconds: TimeInterval? {
let csvTopProductsFrags = split(separator: "-")
guard csvTopProductsFrags.count == 4 else {
return nil
}
guard csvTopProductsFrags[0] == "top30" else {
return nil
}
let hourNames = csvTopProductsFrags[3].split(separator: ".")
guard hourNames.count == 2, let (hour, min, sec) = String(hourNames[0]).HHmmss else {
return nil
}
return TimeInterval(hour * 60 * 60 + min * 60 + sec)
}
func diffSecondsTwoCsvHHmmss(_ another: String) -> TimeInterval {
(csvHHmmssBySeconds ?? 0) - (another.csvHHmmssBySeconds ?? 0)
}
}

View File

@@ -0,0 +1,17 @@
//
// KissIndex+0006.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
import KissMe
extension KissIndex {
func indexSet_0006(date: Date, config: String?, kmi: KissIndexType) {
// TODO: work
}
}

View File

@@ -0,0 +1,111 @@
//
// KissIndex.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
import KissMe
enum KissIndexType: String {
case _0001 = "KMI-0001"
case _0002 = "KMI-0002"
case _0003 = "KMI-0003"
case _0004 = "KMI-0004"
case _0005 = "KMI-0005"
case _0006 = "KMI-0006"
}
class KissIndex {
func run() {
guard CommandLine.argc >= 4 else {
let appName = (CommandLine.arguments[0] as NSString).lastPathComponent
print("\(appName) KMI-0001 yyyyMMdd HHmmss [config.json]")
return
}
guard let kmi = CommandLine.arguments[1].kmiIndex else {
print("Invalid KMI index name")
return
}
let day = CommandLine.arguments[2]
let hour = CommandLine.arguments[3]
guard let date = Date.date(yyyyMMdd: day, HHmmss: hour) else {
print("Invalid timestamp: \(day) \(hour)")
return
}
let config: String?
if CommandLine.argc >= 5 {
config = CommandLine.arguments[4]
}
else {
config = nil
}
let kmiType = KissIndexType(rawValue: kmi)
switch kmiType {
case ._0001:
indexSet_0001(date: date, config: config, kmi: kmiType!)
case ._0002:
indexSet_0002(date: date, config: config, kmi: kmiType!)
case ._0003:
indexSet_0003(date: date, config: config, kmi: kmiType!)
case ._0004:
indexSet_0004(date: date, config: config, kmi: kmiType!)
case ._0005:
indexSet_0005(date: date, config: config, kmi: kmiType!)
case ._0006:
indexSet_0006(date: date, config: config, kmi: kmiType!)
default:
print("Unsupported index set: \(kmi)")
}
}
func writeError(_ error: Error, kmi: KissIndexType) {
let result = KissIndexResult(code: 300, message: error.localizedDescription, kmi: kmi.rawValue, output: [])
do {
let jsonData = try JSONEncoder().encode(result)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)
} catch {
assertionFailure(error.localizedDescription)
}
}
func writeOutput(_ output: [KissIndexResult.Output], kmi: KissIndexType) {
let result = KissIndexResult(code: 200, message: "OK", kmi: kmi.rawValue, output: output)
do {
let jsonData = try JSONEncoder().encode(result)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)
} catch {
assertionFailure(error.localizedDescription)
}
}
// private func isHoliday(_ date: Date) -> Bool {
//
// }
}
extension String {
var kmiIndex: String? {
guard utf8.count == 8, String(prefix(4)).uppercased() == "KMI-" else {
return nil
}
let index = String(suffix(4))
guard let _ = Int(index) else {
return nil
}
return "KMI-\(index)"
}
}

View File

@@ -0,0 +1,10 @@
//
// main.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/19.
//
import Foundation
KissIndex().run()

View File

@@ -0,0 +1,16 @@
//
// KissMatrix.swift
// KissMeMatrix
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
class KissMatrix {
func run() {
}
}

View File

@@ -7,5 +7,4 @@
import Foundation
print("Hello, World!")
KissMatrix().run()

View File

@@ -57,6 +57,46 @@ WIP `showcase` | 추천 상품을 제안함.
* 평균거래금액회전율: atvtr (average-transaction-value-turnover-rate)
# KissMeIndex
KissMeIndex 는 지표 집합(index set)을 추출하는 도구입니다.
## INPUT
INPUT 으로는 다음과 같은 값을 제공합니다.
* 환경설정 : config.json 파일로 특정 지표에서 보정으로 필요로 하는 설정을 기입합니다.
* 현재시간 : timestamp 값을 반드시 필요로 합니다. simulator 에서도 이 기능을 활용할 수 있습니다.
## OUTPUT
OUTPUT 은 다음과 같은 값을 json 형태로 제공합니다.
* shortCode : 추천종목 코드 번호입니다.
* weight : [-1.0, 1.0] 사이의 가중치 값입니다. 음수이면 매도 성향이고, 양수이면 매수성향입니다.
## Example
```bash
./KissMeIndex KMI-0001 20230616 100000 config.json
{
"code": 200,
"message": "OK",
"kmi": "KMI-0005",
"output": [
{
"shortCode": "005930",
"weight": -1.0
},
{
"shortCode": "247540",
"weight": 0.5
}
]
}
```
# KissMeMatrix
KissMeMatrix 는 다양한 주식의 지표 집합(index set) 통해서 교집합 종목을 찾아내는 데이터 모델 도구입니다.

11
documents/KMI/KMI-0001.md Normal file
View File

@@ -0,0 +1,11 @@
# KMI-0001
일봉을 기준으로 최근의 변화량을 분석한 지표입니다.
RSI, MACD 를 계산해서 종목을 추천합니다.
## 변경내역
* 2023-06-17
* RSI 의 분석을 실시간이 아닌 어제 데이터 기준으로 처리 대응.
* 실시간 데이터로 처리하는 것은 현재 ROI 가 적절하지 않음.

View File

@@ -0,0 +1,2 @@
# KMI-0002

View File

@@ -0,0 +1,2 @@
# KMI-0003

View File

@@ -0,0 +1,2 @@
# KMI-0004

31
documents/KMI/KMI-0005.md Normal file
View File

@@ -0,0 +1,31 @@
# KMI-0005
## How to
한국투자증권에서 제공하는 [거래량 순위 API](https://apiportal.koreainvestment.com/apiservice/apiservice-domestic-stock-quotations#L_6df56964-f22b-43d4-9457-f06264018e5b) 로부터 TOP 30 종목을 10분마다 얻은 데이터를 기반으로 산출합니다.
* 거래량순위[v1_국내주식-047]
* /uapi/domestic-stock/v1/quotations/volume-rank
여기에는 다음의 5가지의 분류 항목이 있습니다.
1. 평균거래량
2. 거래증가율
3. 평균거래회전율
4. 거래금액순
5. 평균거래금액회전율
1~30등까지 각 30점에서 1점까지 부여하고, 5가지 분류에 대해서 합집합을 구합니다. 합집합을 계산할 때 정규화하여 얻습니다.
## Usage
다음은 Index 데이터를 추출하는 방법입니다.
```bash
./KissMeIndex KMI-0005 20230618 105922 config.json
```
## Configuration
현재 여기에는 환경설정 정보가 없습니다.

View File

@@ -0,0 +1,2 @@
# KMI-0006

9
documents/README.md Normal file
View File

@@ -0,0 +1,9 @@
# KMI (Kiss Me Index)
* [KMI-0001](KMI/KMI-0001.md)
* [KMI-0002](KMI/KMI-0002.md)
* [KMI-0003](KMI/KMI-0003.md)
* [KMI-0004](KMI/KMI-0004.md)
* [KMI-0005](KMI/KMI-0005.md)
* [KMI-0006](KMI/KMI-0006.md)

View File

@@ -36,6 +36,8 @@
3435A7F72A35D82000D604F1 /* DomesticShortSelling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3435A7F62A35D82000D604F1 /* DomesticShortSelling.swift */; };
349C26AB2A1EAE2400F3EC91 /* KissProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */; };
34D3680F2A2AA0BE005E6756 /* PropertyIterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */; };
34F190092A418E130068C697 /* LocalContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F190082A418E130068C697 /* LocalContext.swift */; };
34F1900C2A41982A0068C697 /* IndexResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F1900B2A41982A0068C697 /* IndexResult.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -79,6 +81,8 @@
3435A7F62A35D82000D604F1 /* DomesticShortSelling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticShortSelling.swift; sourceTree = "<group>"; };
349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissProfile.swift; sourceTree = "<group>"; };
34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyIterable.swift; sourceTree = "<group>"; };
34F190082A418E130068C697 /* LocalContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalContext.swift; sourceTree = "<group>"; };
34F1900B2A41982A0068C697 /* IndexResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexResult.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -121,6 +125,7 @@
341F5EAD2A0A80EC00962D48 /* KissMe */ = {
isa = PBXGroup;
children = (
34F1900A2A41981A0068C697 /* Index */,
341F5EF32A0F88AC00962D48 /* Common */,
341F5EEA2A0F882300962D48 /* Foreign */,
341F5EE62A0F3EFB00962D48 /* Domestic */,
@@ -190,6 +195,7 @@
341F5F022A11A2BC00962D48 /* Credential.swift */,
341F5F062A14634F00962D48 /* Foundation+Extensions.swift */,
34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */,
34F190082A418E130068C697 /* LocalContext.swift */,
);
path = Common;
sourceTree = "<group>";
@@ -210,6 +216,14 @@
path = ShortSelling;
sourceTree = "<group>";
};
34F1900A2A41981A0068C697 /* Index */ = {
isa = PBXGroup;
children = (
34F1900B2A41982A0068C697 /* IndexResult.swift */,
);
path = Index;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -330,12 +344,14 @@
341F5EF72A0F8B0500962D48 /* DomesticStockResult.swift in Sources */,
341F5F0F2A15223A00962D48 /* SeibroRequest.swift in Sources */,
341F5EF02A0F886600962D48 /* ForeignFutures.swift in Sources */,
34F1900C2A41982A0068C697 /* IndexResult.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 */,
349C26AB2A1EAE2400F3EC91 /* KissProfile.swift in Sources */,
34F190092A418E130068C697 /* LocalContext.swift in Sources */,
341F5F012A11155100962D48 /* DomesticStockSearchResult.swift in Sources */,
341F5F142A16CD7A00962D48 /* DomesticShopProduct.swift in Sources */,
341F5EF22A0F887200962D48 /* DomesticFutures.swift in Sources */,

View File

@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:KissMeBatch.xcodeproj">
</FileRef>
<FileRef
location = "group:KissMeConsole.xcodeproj">
</FileRef>
@@ -13,6 +10,9 @@
<FileRef
location = "group:KissMeMatrix.xcodeproj">
</FileRef>
<FileRef
location = "group:KissMeIndex.xcodeproj">
</FileRef>
<FileRef
location = "container:KissMe.xcodeproj">
</FileRef>

View File

@@ -13,7 +13,6 @@
3435A7F22A35A8A900D604F1 /* KissConsole+Investor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3435A7F12A35A8A900D604F1 /* KissConsole+Investor.swift */; };
3435A7F42A35B4D000D604F1 /* KissConsole+Price.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3435A7F32A35B4D000D604F1 /* KissConsole+Price.swift */; };
348168492A2F92AC00A50BD3 /* KissContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348168482A2F92AC00A50BD3 /* KissContext.swift */; };
348168692A3420BD00A50BD3 /* LocalContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348168682A3420BD00A50BD3 /* LocalContext.swift */; };
349327F72A20E3E300097063 /* Foundation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349327F62A20E3E300097063 /* Foundation+Extensions.swift */; };
349843212A242AC900E85B08 /* KissConsole+CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349843202A242AC900E85B08 /* KissConsole+CSV.swift */; };
34D3680D2A280801005E6756 /* KissConsole+Candle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D3680C2A280801005E6756 /* KissConsole+Candle.swift */; };
@@ -53,7 +52,6 @@
3435A7F12A35A8A900D604F1 /* KissConsole+Investor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissConsole+Investor.swift"; sourceTree = "<group>"; };
3435A7F32A35B4D000D604F1 /* KissConsole+Price.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissConsole+Price.swift"; sourceTree = "<group>"; };
348168482A2F92AC00A50BD3 /* KissContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissContext.swift; sourceTree = "<group>"; };
348168682A3420BD00A50BD3 /* LocalContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalContext.swift; sourceTree = "<group>"; };
349327F62A20E3E300097063 /* Foundation+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Extensions.swift"; sourceTree = "<group>"; };
3498431E2A24287600E85B08 /* KissMeConsoleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KissMeConsoleTests.swift; sourceTree = "<group>"; };
349843202A242AC900E85B08 /* KissConsole+CSV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissConsole+CSV.swift"; sourceTree = "<group>"; };
@@ -95,7 +93,6 @@
children = (
341F5ED32A0A8B9000962D48 /* main.swift */,
341F5F042A13B82F00962D48 /* test.swift */,
348168682A3420BD00A50BD3 /* LocalContext.swift */,
348168482A2F92AC00A50BD3 /* KissContext.swift */,
341F5F082A1463A100962D48 /* KissConsole.swift */,
34D3680C2A280801005E6756 /* KissConsole+Candle.swift */,
@@ -190,7 +187,6 @@
341F5F092A1463A100962D48 /* KissConsole.swift in Sources */,
3435A7F22A35A8A900D604F1 /* KissConsole+Investor.swift in Sources */,
341F5F052A13B82F00962D48 /* test.swift in Sources */,
348168692A3420BD00A50BD3 /* LocalContext.swift in Sources */,
349843212A242AC900E85B08 /* KissConsole+CSV.swift in Sources */,
348168492A2F92AC00A50BD3 /* KissContext.swift in Sources */,
3435A7F42A35B4D000D604F1 /* KissConsole+Price.swift in Sources */,

View File

@@ -0,0 +1,343 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objects = {
/* Begin PBXBuildFile section */
34F18FEB2A3FA2CA0068C697 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FEA2A3FA2CA0068C697 /* main.swift */; };
34F18FF22A41299D0068C697 /* KissIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FF12A41299D0068C697 /* KissIndex.swift */; };
34F18FF52A4148950068C697 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F18FF42A4148950068C697 /* KissMe.framework */; };
34F18FF62A4148950068C697 /* KissMe.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 34F18FF42A4148950068C697 /* KissMe.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34F18FF92A41544E0068C697 /* KissIndex+0006.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FF82A41544E0068C697 /* KissIndex+0006.swift */; };
34F18FFB2A4155750068C697 /* KissIndex+0005.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FFA2A4155750068C697 /* KissIndex+0005.swift */; };
34F18FFD2A4155890068C697 /* KissIndex+0004.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FFC2A4155890068C697 /* KissIndex+0004.swift */; };
34F18FFF2A4155BF0068C697 /* KissIndex+0003.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F18FFE2A4155BF0068C697 /* KissIndex+0003.swift */; };
34F190012A4155D70068C697 /* KissIndex+0002.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F190002A4155D70068C697 /* KissIndex+0002.swift */; };
34F190032A4155F90068C697 /* KissIndex+0001.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F190022A4155F90068C697 /* KissIndex+0001.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
34F18FE52A3FA2CA0068C697 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
34F18FF72A4148950068C697 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
34F18FF62A4148950068C697 /* KissMe.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
34F18FE72A3FA2CA0068C697 /* KissMeIndex */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KissMeIndex; sourceTree = BUILT_PRODUCTS_DIR; };
34F18FEA2A3FA2CA0068C697 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
34F18FF12A41299D0068C697 /* KissIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissIndex.swift; sourceTree = "<group>"; };
34F18FF42A4148950068C697 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
34F18FF82A41544E0068C697 /* KissIndex+0006.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0006.swift"; sourceTree = "<group>"; };
34F18FFA2A4155750068C697 /* KissIndex+0005.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0005.swift"; sourceTree = "<group>"; };
34F18FFC2A4155890068C697 /* KissIndex+0004.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0004.swift"; sourceTree = "<group>"; };
34F18FFE2A4155BF0068C697 /* KissIndex+0003.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0003.swift"; sourceTree = "<group>"; };
34F190002A4155D70068C697 /* KissIndex+0002.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0002.swift"; sourceTree = "<group>"; };
34F190022A4155F90068C697 /* KissIndex+0001.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KissIndex+0001.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
34F18FE42A3FA2CA0068C697 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
34F18FF52A4148950068C697 /* KissMe.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
34F18FDE2A3FA2CA0068C697 = {
isa = PBXGroup;
children = (
34F18FE92A3FA2CA0068C697 /* KissMeIndex */,
34F18FE82A3FA2CA0068C697 /* Products */,
34F18FF32A4148950068C697 /* Frameworks */,
);
sourceTree = "<group>";
};
34F18FE82A3FA2CA0068C697 /* Products */ = {
isa = PBXGroup;
children = (
34F18FE72A3FA2CA0068C697 /* KissMeIndex */,
);
name = Products;
sourceTree = "<group>";
};
34F18FE92A3FA2CA0068C697 /* KissMeIndex */ = {
isa = PBXGroup;
children = (
34F18FEA2A3FA2CA0068C697 /* main.swift */,
34F18FF12A41299D0068C697 /* KissIndex.swift */,
34F190022A4155F90068C697 /* KissIndex+0001.swift */,
34F190002A4155D70068C697 /* KissIndex+0002.swift */,
34F18FFE2A4155BF0068C697 /* KissIndex+0003.swift */,
34F18FFC2A4155890068C697 /* KissIndex+0004.swift */,
34F18FFA2A4155750068C697 /* KissIndex+0005.swift */,
34F18FF82A41544E0068C697 /* KissIndex+0006.swift */,
);
name = KissMeIndex;
path = ../../KissMeIndex/Sources;
sourceTree = "<group>";
};
34F18FF32A4148950068C697 /* Frameworks */ = {
isa = PBXGroup;
children = (
34F18FF42A4148950068C697 /* KissMe.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
34F18FE62A3FA2CA0068C697 /* KissMeIndex */ = {
isa = PBXNativeTarget;
buildConfigurationList = 34F18FEE2A3FA2CA0068C697 /* Build configuration list for PBXNativeTarget "KissMeIndex" */;
buildPhases = (
34F18FE32A3FA2CA0068C697 /* Sources */,
34F18FE42A3FA2CA0068C697 /* Frameworks */,
34F18FE52A3FA2CA0068C697 /* CopyFiles */,
34F18FF72A4148950068C697 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = KissMeIndex;
productName = KissMeIndex;
productReference = 34F18FE72A3FA2CA0068C697 /* KissMeIndex */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
34F18FDF2A3FA2CA0068C697 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1430;
LastUpgradeCheck = 1430;
TargetAttributes = {
34F18FE62A3FA2CA0068C697 = {
CreatedOnToolsVersion = 14.3.1;
};
};
};
buildConfigurationList = 34F18FE22A3FA2CA0068C697 /* Build configuration list for PBXProject "KissMeIndex" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 34F18FDE2A3FA2CA0068C697;
productRefGroup = 34F18FE82A3FA2CA0068C697 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
34F18FE62A3FA2CA0068C697 /* KissMeIndex */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
34F18FE32A3FA2CA0068C697 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
34F190012A4155D70068C697 /* KissIndex+0002.swift in Sources */,
34F18FFD2A4155890068C697 /* KissIndex+0004.swift in Sources */,
34F18FFF2A4155BF0068C697 /* KissIndex+0003.swift in Sources */,
34F18FF92A41544E0068C697 /* KissIndex+0006.swift in Sources */,
34F18FFB2A4155750068C697 /* KissIndex+0005.swift in Sources */,
34F190032A4155F90068C697 /* KissIndex+0001.swift in Sources */,
34F18FF22A41299D0068C697 /* KissIndex.swift in Sources */,
34F18FEB2A3FA2CA0068C697 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
34F18FEC2A3FA2CA0068C697 /* 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;
};
34F18FED2A3FA2CA0068C697 /* 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;
};
34F18FEF2A3FA2CA0068C697 /* 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;
};
34F18FF02A3FA2CA0068C697 /* 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 */
34F18FE22A3FA2CA0068C697 /* Build configuration list for PBXProject "KissMeIndex" */ = {
isa = XCConfigurationList;
buildConfigurations = (
34F18FEC2A3FA2CA0068C697 /* Debug */,
34F18FED2A3FA2CA0068C697 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
34F18FEE2A3FA2CA0068C697 /* Build configuration list for PBXNativeTarget "KissMeIndex" */ = {
isa = XCConfigurationList;
buildConfigurations = (
34F18FEF2A3FA2CA0068C697 /* Debug */,
34F18FF02A3FA2CA0068C697 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 34F18FDF2A3FA2CA0068C697 /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View 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>

View File

@@ -0,0 +1,85 @@
<?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 = "34F18FE62A3FA2CA0068C697"
BuildableName = "KissMeIndex"
BlueprintName = "KissMeIndex"
ReferencedContainer = "container:KissMeIndex.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 = "34F18FE62A3FA2CA0068C697"
BuildableName = "KissMeIndex"
BlueprintName = "KissMeIndex"
ReferencedContainer = "container:KissMeIndex.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "KMI-0005 20230616 100000"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34F18FE62A3FA2CA0068C697"
BuildableName = "KissMeIndex"
BlueprintName = "KissMeIndex"
ReferencedContainer = "container:KissMeIndex.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -10,6 +10,7 @@
349843492A24DBF700E85B08 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349843482A24DBF700E85B08 /* main.swift */; };
349843692A24DC7F00E85B08 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 349843682A24DC7F00E85B08 /* KissMe.framework */; };
3498436A2A24DC7F00E85B08 /* KissMe.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 349843682A24DC7F00E85B08 /* KissMe.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
34F190052A4156500068C697 /* KissMatrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F190042A4156500068C697 /* KissMatrix.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -39,6 +40,7 @@
349843452A24DBF700E85B08 /* KissMeMatrix */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KissMeMatrix; sourceTree = BUILT_PRODUCTS_DIR; };
349843482A24DBF700E85B08 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
349843682A24DC7F00E85B08 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
34F190042A4156500068C697 /* KissMatrix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissMatrix.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -74,6 +76,7 @@
isa = PBXGroup;
children = (
349843482A24DBF700E85B08 /* main.swift */,
34F190042A4156500068C697 /* KissMatrix.swift */,
);
name = KissMeMatrix;
path = ../../KissMeMatrix/Sources;
@@ -146,6 +149,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
34F190052A4156500068C697 /* KissMatrix.swift in Sources */,
349843492A24DBF700E85B08 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;